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): add validateTrigger, setFieldValue and disabled #2772

Merged
merged 12 commits into from
Dec 6, 2024

Conversation

oasis-cloud
Copy link
Collaborator

@oasis-cloud oasis-cloud commented Nov 19, 2024

🤔 这个变动的性质是?

  • 新特性提交
  • 日常 bug 修复
  • 站点、文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • TypeScript 定义更新
  • 包体积优化
  • 性能优化
  • 功能增强
  • 国际化改进
  • 重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他改动(是关于什么的改动?)

🔗 相关 Issue

💡 需求背景和解决方案

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项⚠️

  • 文档已补充或无须补充
  • 代码演示已提供或无须提供
  • TypeScript 定义已补充或无须补充
  • fork仓库代码是否为最新避免文件冲突
  • Files changed 没有 package.json lock 等无关文件

Summary by CodeRabbit

  • 新特性

    • 更新了 Form 组件的文档,新增 disabledvalidateTrigger 属性,增强了表单的功能和可配置性。
    • 新增 setFieldValue 方法,允许按名称设置特定字段的值。
  • 样式

    • 移除了多个与表单布局相关的 CSS 规则,简化了样式处理。
    • 更新了 .nut-form-item 组件的样式,添加了新的类以支持禁用状态和必填标签的样式。
  • 测试

    • 更新了 Form 组件的测试用例,确保验证逻辑和初始值设置的准确性。

Copy link

coderabbitai bot commented Nov 19, 2024

Walkthrough

该拉取请求主要更新了Form组件的文档和相关代码,新增了disabledvalidateTrigger属性,增强了表单字段的管理和验证功能。文档中对setFieldsValuesetFieldValue方法进行了详细说明,确保用户能够正确使用这些功能。此外,CSS样式也进行了简化,移除了特定布局的样式,增强了组件的灵活性。

Changes

文件路径 修改摘要
src/packages/form/doc.en-US.md 更新了Form组件文档,新增disabledvalidateTrigger属性,修改setFieldsValue和新增setFieldValue方法说明。
src/packages/form/doc.md 更新了FormForm.Item组件文档,新增validateTrigger属性,修改setFieldsValue和新增setFieldValue方法说明。
src/packages/form/doc.taro.md 更新了Form组件文档,新增validateTriggerdisabled属性,修改setFieldsValue和新增setFieldValue方法说明。
src/packages/form/doc.zh-TW.md 更新了Form组件文档,新增validateTriggerdisabled属性,修改setFieldsValue和新增setFieldValue方法说明。
src/packages/form/form.scss 移除了与表单布局相关的CSS规则,简化了样式处理。
src/packages/form/form.taro.tsx 更新FormProps接口,新增disabledvalidateTrigger属性,修改组件内部逻辑以支持新属性。
src/packages/form/form.tsx 更新FormProps接口,新增disabledvalidateTrigger属性,修改上下文提供的值以包含新属性。
src/packages/form/types.ts 更新接口,新增regex属性和setFieldValue方法,修改setFieldsValue方法参数类型。
src/packages/form/useform.taro.ts 更新FormStore类,新增updateStoresetFieldValue方法,修改setInitialValuessetFieldsValue方法。
src/packages/form/useform.ts 更新FormStore类,新增updateStoresetFieldValue方法,修改setInitialValuessetFieldsValue方法。
src/packages/formitem/formitem.scss 更新样式,新增.nut-form-item-disabled类,修改.nut-form-item-label类,新增多个布局相关类。
src/packages/formitem/formitem.taro.tsx 更新FormItem组件,修改上下文处理,更新validateTrigger属性为可选。
src/packages/formitem/formitem.tsx 更新FormItem组件,修改上下文访问方式,更新验证触发逻辑。
src/utils/merge.ts 新增merge函数,用于合并多个对象。
src/utils/to-array.ts 新增toArray函数,确保输出始终为数组。
src/packages/form/__tests__/form.spec.tsx 更新测试用例,确保验证逻辑和初始值设置的准确性。

Possibly related PRs

Suggested labels

size/L, 3.x

Suggested reviewers

  • xiaoyatong

兔子欢快跳跃,
表单更新真美妙。
属性新增不怕难,
功能增强乐逍遥。
验证触发更灵活,
代码清晰如晨曦。 🐇✨


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.

@github-actions github-actions bot added the 2.x label Nov 19, 2024
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: 9

🧹 Outside diff range and nitpick comments (20)
src/packages/form/form.tsx (1)

14-14: 建议为新增的属性添加 JSDoc 注释

为了提高代码的可维护性和可读性,建议为新增的 disabledvalidateTrigger 属性添加详细的 JSDoc 注释,说明其用途和可选值。

建议添加如下注释:

+/** 是否禁用表单内所有组件 */
 disabled: boolean
 divider: boolean
+/** 
+ * 触发验证的时机
+ * @type {string | string[] | false} 可以是字符串,字符串数组或 false
+ * @default 'onChange'
+ */
 validateTrigger: string | string[] | false

Also applies to: 16-16

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

51-51: 建议增强 disabled 状态的处理

当前实现将 disabled 状态通过 Context 传递给子组件,建议考虑以下优化:

  1. 在表单级别统一处理 disabled 状态
  2. 为表单容器添加 disabled 状态的样式类
  3. 提供禁用状态下的视觉反馈
<TForm
- className={classNames(classPrefix, PositionInfo[labelPosition], className)}
+ className={classNames(
+   classPrefix,
+   PositionInfo[labelPosition],
+   { [`${classPrefix}-disabled`]: disabled },
+   className
+ )}

51-54: 属性解构需要考虑性能优化

从 props 中解构新增属性的方式正确,但建议考虑使用 useMemo 优化性能,特别是在表单项较多的场景下。

建议改进如下:

+ const memoizedProps = React.useMemo(() => ({
+   ...defaultProps,
+   ...props,
+ }), [props]);

  const {
    className,
    style,
    footer,
    children,
    initialValues,
    divider,
    disabled,
    onFinish,
    onFinishFailed,
    validateTrigger,
    labelPosition,
    starPosition,
    form,
- } = {
-   ...defaultProps,
-   ...props,
- }
+ } = memoizedProps;
src/packages/formitem/formitem.scss (2)

10-16: 建议优化标签文本大小以提高可访问性

虽然布局结构合理,但标签文本大小(12px)可能影响可读性,特别是对于视力不佳的用户。建议:

  1. 考虑增加文本大小至少到 14px
  2. 确保符合 WCAG 标准的对比度要求
 .nut-form-item-labeltxt {
-  font-size: 12px;
+  font-size: 14px;
   height: 10px;
 }

Also applies to: 21-28


110-144: 建议使用 CSS 变量替代固定数值

当前实现使用了多个固定的内边距值(如 24px, 12px),建议:

  1. 将这些值转换为 CSS 变量
  2. 统一管理间距变量
+ :root {
+   --nut-form-padding-lg: 24px;
+   --nut-form-padding-md: 12px;
+ }

 .nut-form-item-label-right {
-  padding-right: 24px;
+  padding-right: var(--nut-form-padding-lg);
 }

 .nut-form-item-label-left {
-  padding-left: 12px;
+  padding-left: var(--nut-form-padding-md);
 }
src/packages/form/doc.md (2)

81-81: 建议补充 validateTrigger 的可选值说明

为了帮助开发者更好地理解和使用这个属性,建议补充具体的可选值(如:onChangeonBlur 等)以及相应的使用场景说明。

-| validateTrigger | 统一设置字段触发验证的时机 | `string` \| `string[]` | `onChange` |
+| validateTrigger | 统一设置字段触发验证的时机。可选值:`onChange`、`onBlur`。支持数组形式同时设置多个触发时机 | `string` \| `string[]` | `onChange` |

128-129: 建议为 setFieldsValue 和 setFieldValue 添加使用示例

为了提高文档的实用性,建议为这两个方法添加具体的使用示例,帮助开发者理解它们的区别和正确用法。

-| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入) | `(values) => void` |
-| setFieldValue | 设置对应字段名的值 | `<T>(name: NamePath, value: T) => void` |
+| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入)。示例:`form.setFieldsValue({ username: 'nutui', password: '123456' })` | `(values) => void` |
+| setFieldValue | 设置对应字段名的值。示例:`form.setFieldValue('username', 'nutui')` | `<T>(name: NamePath, value: T) => void` |
src/packages/form/doc.zh-TW.md (2)

82-82: 建议补充 validateTrigger 的使用示例

为了帮助开发者更好地理解 validateTrigger 属性的使用方法,建议在文档中添加具体的代码示例,展示不同触发时机的效果。

建议添加如下示例:

| validateTrigger | 統一設定字段觸發驗證的時機 | `string` \| `string[]` | `onChange` |
+
+例如:
+```tsx
+<Form validateTrigger="onBlur">
+  <Form.Item>
+    {/* 在失焦时触发验证 */}
+  </Form.Item>
+</Form>
+
+<Form validateTrigger={['onChange', 'onBlur']}>
+  <Form.Item>
+    {/* 在值变化和失焦时都触发验证 */}
+  </Form.Item>
+</Form>
+```

128-129: 完善 setFieldsValue 和 setFieldValue 的文档说明

建议补充这两个方法的使用示例,并说明它们之间的区别,以帮助开发者选择合适的方法。

建议添加如下内容:

| setFieldsValue | 設定表單的值(該值將直接傳入 form store 中。如果你不希望傳入物件被修改,請複製後傳入) | `(values) => void` |
| setFieldValue | 設定對應欄位名的值 | `<T>(name: NamePath, value: T) => void` |
+
+例如:
+```tsx
+// 使用 setFieldsValue 同时设置多个字段
+form.setFieldsValue({
+  username: 'nutui',
+  password: '123456'
+});
+
+// 使用 setFieldValue 设置单个字段
+form.setFieldValue('username', 'nutui');
+```
+
+注意:
+- setFieldsValue 用于批量设置多个字段的值
+- setFieldValue 用于设置单个字段的值,使用更简便
src/packages/form/doc.taro.md (2)

81-81: 建议补充 validateTrigger 的可选值说明

为了帮助开发者更好地理解和使用这个属性,建议补充:

  • 可选值列表(例如:'onChange'、'onBlur' 等)
  • 使用数组时的示例(如:['onChange', 'onBlur']
  • 不同触发时机的应用场景说明

128-129: 建议添加方法使用示例

为了使文档更加完整和易于理解,建议为这两个方法添加示例代码:

  • setFieldsValue 的对象克隆示例
  • setFieldValue 的基础使用示例
  • 两种方法的区别对比示例

示例可以添加在方法说明后面,格式如下:

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

// setFieldValue 示例
form.setFieldValue('username', 'nutui');
src/packages/form/doc.en-US.md (2)

83-83: 建议增加 validateTrigger 的使用示例

validateTrigger 属性的基本描述已经提供,但为了帮助开发者更好地理解和使用这个新功能,建议:

  1. 添加支持的具体触发时机(例如:'onBlur','onChange' 等)
  2. 提供多个触发器的示例代码
 | validateTrigger | uniformly set the timing for fields to trigger validation | `string` \| `string[]` | `onChange` |
+
+Example:
+```tsx
+// Single trigger
+<Form validateTrigger="onBlur">
+  
+// Multiple triggers
+<Form validateTrigger={['onChange', 'onBlur']}>
+```

129-129: 建议为 setFieldsValue 添加代码示例

对于对象可能被修改的警告很重要,但建议添加具体示例来说明正确的使用方式。

 | setFieldsValue | Set the value of the form (the value will be passed directly to the form store. If you do not want the object passed in to be modified, please copy it and pass it in) | `(values) => void` |
+
+Example:
+```tsx
+// 直接设置(对象可能被修改)
+form.setFieldsValue({ name: 'value' });
+
+// 使用对象拷贝(推荐)
+form.setFieldsValue({ ...originalObject });
+```
src/packages/form/useform.taro.ts (2)

78-80: store更新逻辑集中化处理

将store的更新逻辑集中到updateStore方法中是个很好的实践,建议考虑添加一个简单的注释说明该方法的用途。

+  /**
+   * 更新表单存储的数据
+   * @param nextStore 新的数据对象
+   */
  updateStore(nextStore: Store) {
    this.store = nextStore
  }

138-142: 表单字段验证提示优化

当前的警告信息可以更加具体,建议包含更多上下文信息以帮助开发者快速定位问题。

-      console.warn('Form field missing name property')
+      console.warn('Form validation failed: field missing required "name" property. Please ensure all form fields have a unique name.')
src/packages/formitem/formitem.tsx (3)

78-79: 建议:考虑封装内部访问逻辑

多处使用 formInstance.getInternal(SECRET) 获取内部状态,建议将这个访问模式封装到一个工具方法中,以提高代码的可维护性和一致性。

建议创建一个工具方法:

private getFormInternals() {
  return this.context.formInstance.getInternal(SECRET);
}

Also applies to: 91-92


195-200: 类名处理优化建议

getClassNameWithDirection 方法的实现可以进一步优化:

  1. 考虑使用类名管理库(如 classnames)来处理条件类名
  2. 可以将类名常量抽取为配置项
  3. 建议添加空值检查

建议的改进实现:

import classNames from 'classnames';

private getClassNameWithDirection(baseClassName?: string) {
  if (!baseClassName) return '';
  
  return classNames(baseClassName, {
    [`${baseClassName}-${this.context.labelPosition}`]: this.context.labelPosition
  });
}

Also applies to: 233-233, 241-243, 247-249


279-283: 禁用状态处理建议

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

  1. 建议使用 CSS-in-JS 或 CSS 模块来避免类名冲突
  2. 考虑将禁用状态的样式逻辑移至样式文件中
  3. 建议添加 aria-disabled 属性以提高可访问性

建议的实现:

-<div className={this.context.disabled ? 'nut-form-item-disabled' : ''}>
+<div 
+  className={classNames({
+    'nut-form-item-disabled': this.context.disabled
+  })}
+  aria-disabled={this.context.disabled}
+>
src/packages/form/useform.ts (2)

78-81: 建议将updateStore方法设为私有

目前,updateStore方法没有指定访问修饰符。为了提高类的封装性和安全性,建议在方法前添加private关键字,使其仅在类内部可访问。


176-190: validateFields方法的错误收集方式可以优化

当前,validateFields方法将所有错误收集到数组errs中,可能难以直接关联到具体的字段。建议使用对象来映射字段名到错误信息,便于后续处理和展示。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 66e9d1b and de14e46.

📒 Files selected for processing (13)
  • 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.scss (0 hunks)
  • src/packages/form/form.taro.tsx (6 hunks)
  • src/packages/form/form.tsx (4 hunks)
  • src/packages/form/types.ts (2 hunks)
  • src/packages/form/useform.taro.ts (8 hunks)
  • src/packages/form/useform.ts (7 hunks)
  • src/packages/formitem/formitem.scss (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (10 hunks)
  • src/packages/formitem/formitem.tsx (10 hunks)
💤 Files with no reviewable changes (1)
  • src/packages/form/form.scss
🧰 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)

🔇 Additional comments (22)
src/packages/form/types.ts (3)

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

通过添加可选的 regex 属性,增强了表单验证规则的灵活性。类型定义正确且符合 TypeScript 最佳实践。


24-24: 泛型类型参数的使用恰当

setFieldValue 方法的定义使用了泛型参数 T,这样可以在运行时保持类型安全性,同时保持了与现有 API 的一致性。


26-26: 类型约束更加严格

setFieldsValue 的参数类型从 any 改为 Store 接口是一个很好的改进,这样可以:

  1. 提供更好的类型安全性
  2. 确保传入的值结构符合预期
  3. 提供更好的 IDE 支持和代码提示
src/packages/form/form.tsx (2)

27-27: 默认值设置合理

新增属性的默认值设置符合常见表单组件的使用习惯,disabled 默认为 falsevalidateTrigger 默认为 'onChange'

Also applies to: 29-29


105-109: 需要验证子组件对新增 Context 值的处理

Context 值的结构发生了变化,新增了 disabledvalidateTrigger 属性。请确保所有消费该 Context 的子组件都正确处理了这些新属性。

运行以下脚本来检查使用该 Context 的子组件:

✅ Verification successful

Let me gather more specific information about the Context usage in these components.


Let me try another approach to find the Context usage patterns.


Context 值的变更已被正确处理

通过代码分析发现:

  • FormItem 组件已正确使用 disabledvalidateTrigger 属性:
    • disabled 用于控制表单项的禁用状态和样式
    • validateTrigger 被用于表单验证触发机制
  • 这些属性在 H5 和 Taro 版本中都得到了正确实现
  • FormItem 组件支持从 Context 和 props 中获取这些值,并正确处理了优先级

因此,Context 值的变更是安全的,相关子组件已经实现了对新增属性的完整支持。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:查找所有使用 Form Context 的组件

# 搜索使用 Context 的组件
ast-grep --pattern 'useContext($context)' 

# 搜索可能受影响的表单相关组件
fd -e tsx -e ts -e jsx -e js | xargs rg -l "from ['\"].*form.*['\"]"

Length of output: 534


Script:

#!/bin/bash
# 查找使用 Form Context 的具体实现
ast-grep --pattern 'const $_ = useContext($context)'

# 查找 FormContext 的定义
rg -A 2 "createContext" src/packages/form/

# 检查 FormItem 组件中的 Context 使用
rg -A 5 "useContext" src/packages/formitem/

Length of output: 332


Script:

#!/bin/bash
# 搜索 Context 的使用模式,包括解构形式
ast-grep --pattern 'const { $$$_ } = useContext($context)'

# 查找表单组件中对 Context 值的使用
rg -B 2 -A 5 "Context" src/packages/formitem/
rg -B 2 -A 5 "Context" src/packages/form/demos/

# 检查是否有直接使用 disabled 和 validateTrigger 的代码
rg "disabled|validateTrigger" src/packages/formitem/

Length of output: 4059

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

15-17: 新增的属性定义和默认值设置合理!

disabledvalidateTrigger 的类型定义清晰,默认值设置符合常见表单组件的使用习惯。

Also applies to: 28-30


Line range hint 87-115: 请验证 TForm 组件的事件处理兼容性

表单组件从 HTML form 切换到 Taro TForm 是必要的改动,但需要确认以下几点:

  1. submit 和 reset 事件在各端是否都能正常触发
  2. 事件阻止传播的方法在小程序环境中是否有效

15-17: 新增的属性类型定义合理且完整

FormProps 接口中新增的 disabledvalidateTrigger 属性定义清晰,类型设计合理。validateTrigger 支持字符串、字符串数组或 false 值,提供了足够的灵活性。


28-30: 默认值设置恰当

为新增属性设置了合理的默认值:

  • disabled: false 默认启用表单
  • validateTrigger: 'onChange' 默认在值变化时触发验证

Line range hint 87-115: 表单组件迁移到 Taro 的实现完整

从原生 form 切换到 Taro 的 TForm 组件实现完整,事件处理保持一致。但建议验证以下几点:

  1. 确保在小程序环境下表单提交和重置行为符合预期
  2. 验证 preventDefault 和 stopPropagation 在小程序中的效果
src/packages/formitem/formitem.scss (3)

4-6: 禁用状态样式实现得当!

使用 opacity 和 pointer-events 来实现禁用状态是一个标准且有效的方案。


31-31: 表单布局结构合理

使用 flex 布局和统一的内边距处理,保持了表单元素的一致性。

Also applies to: 58-58


146-175: RTL 支持实现完善

为不同布局模式提供了完整的 RTL 支持,确保了在不同书写方向下的正确显示。特别注意到:

  1. 正确处理了文本对齐
  2. 适当调整了内边距方向
  3. 考虑到了必填标记的位置调整
src/packages/form/useform.taro.ts (4)

3-3: 类型定义和工具函数导入优化

新增的类型定义和merge工具函数的导入增强了代码的类型安全性和对象合并的可靠性。

Also applies to: 7-7, 9-9


88-92: 初始值设置逻辑优化

使用merge工具函数来合并初始值和现有store数据,保证了数据更新的一致性和可靠性。


122-126: 新增单字段更新方法

新增的setFieldValue方法提供了更便捷的单字段更新API,简化了开发者的使用体验。


266-266: 类型断言优化

明确的FormInstance类型断言提高了类型安全性,符合TypeScript的最佳实践。

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

114-119: 很好的开发体验改进

添加开发环境下的警告提示,引导开发者使用 initialValue 而不是 defaultValue,这有助于规范代码实践。

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

122-126: 新增的setFieldValue方法实现正确

setFieldValue方法方便了单个字段的更新,实现合理,代码清晰。


246-246: getForm返回的实例中新增了setFieldValue方法

FormInstance增加了setFieldValue方法,增强了表单字段操作的灵活性,符合预期。


266-266: useForm钩子返回类型明确

useForm钩子中,明确了返回类型为FormInstance,提高了类型安全性和代码可读性。


205-206: 🛠️ Refactor suggestion

重置表单时应注意状态的清理

resetFields方法中,使用merge函数合并初始值来重置store。同样需要确保merge函数执行深度合并,以正确重置嵌套的状态。并且,建议在重置时清理this.errors中的错误信息,避免残留。

您可以在重置时清空this.errors

 this.errors.length = 0
+this.errors = {}
 const nextStore = merge({}, this.initialValues)

Likely invalid or redundant comment.


100-102: setFieldsValue中合并新值时注意覆盖问题

setFieldsValue方法中,使用merge函数合并this.storenewStore。需要确保新传入的字段值正确更新,而不影响未更改的字段。请确认合并策略符合预期,避免数据不一致。

您可以运行以下脚本检查setFieldsValue的使用情况:

src/packages/form/doc.en-US.md Show resolved Hide resolved
src/packages/form/doc.en-US.md Outdated Show resolved Hide resolved
src/packages/formitem/formitem.tsx Show resolved Hide resolved
src/packages/formitem/formitem.tsx Outdated Show resolved Hide resolved
src/packages/form/form.taro.tsx Show resolved Hide resolved
src/packages/form/useform.ts Outdated Show resolved Hide resolved
src/packages/form/useform.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: 1

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

1-1: 建议添加类型约束以提高类型安全性

考虑添加类型约束来排除一些不应该被转换为数组的类型(如 object)。

- export function toArray<T>(value?: T | T[] | null): T[] {
+ export function toArray<T extends string | number | boolean | symbol>(value?: T | T[] | null): T[] {
src/utils/merge.ts (5)

1-2: 建议增强类型检查

建议在初始化时添加更严格的类型检查,以处理 objects 为空数组或第一个参数为 null/undefined 的情况。

 export function merge(...objects) {
+  if (!objects.length) return {}
+  if (!objects[0]) return Array.isArray(objects[0]) ? [] : {}
   const result = Array.isArray(objects[0]) ? [] : {}

4-7: 建议添加 TypeScript 类型定义

为了提高代码的可维护性和类型安全性,建议添加 TypeScript 类型定义。

+type MergeObject = Record<string, any>
+
 export function merge(...objects) {
-  const result = Array.isArray(objects[0]) ? [] : {}
+  const result: MergeObject = Array.isArray(objects[0]) ? [] : {}
 
-  function mergeHelper(obj, path = []) {
+  function mergeHelper(obj: MergeObject, path: any[] = []) {

8-10: 建议优化数组合并策略

当前实现直接覆盖数组,可能不适用于所有场景。建议考虑以下几点:

  1. 为数组合并提供可配置的策略选项
  2. 对数组元素进行深度克隆
  3. 考虑添加数组去重选项
 if (Array.isArray(value)) {
-  result[key] = [...value]
+  result[key] = value.map(item => 
+    typeof item === 'object' && item !== null
+      ? merge({}, item)
+      : item
+  )
 }

19-22: 建议增加特殊对象类型的处理

当前实现没有处理 DateRegExp 等特殊对象类型。建议添加对这些类型的支持。

 } else {
-  // Set primitive values
-  result[key] = value
+  // Handle special object types and primitive values
+  result[key] = value instanceof Date
+    ? new Date(value)
+    : value instanceof RegExp
+    ? new RegExp(value)
+    : value
 }

26-28: 建议添加错误处理机制

建议添加 try-catch 块来处理可能的运行时错误,并提供有意义的错误信息。

-  objects.filter((obj) => !!obj).forEach((obj) => mergeHelper(obj))
-  return result
+  try {
+    objects.filter((obj) => !!obj).forEach((obj) => mergeHelper(obj))
+    return result
+  } catch (error) {
+    console.error('合并对象时发生错误:', error)
+    throw new Error(`合并失败: ${error.message}`)
+  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between de14e46 and 6ee015e.

📒 Files selected for processing (2)
  • src/utils/merge.ts (1 hunks)
  • src/utils/to-array.ts (1 hunks)
🔇 Additional comments (3)
src/utils/to-array.ts (3)

1-7: 代码实现清晰简洁!

函数实现符合单一职责原则,类型安全性好,处理了所有边界情况。


2-4: 空值处理逻辑合理

undefinednull 的处理符合预期,返回空数组是一个好的设计选择。


6-6: 实现简洁高效

使用三元运算符使代码更加简洁,同时保持了良好的可读性。

@jdf2e jdf2e deleted a comment from coderabbitai bot Nov 19, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Nov 19, 2024
Copy link

codecov bot commented Nov 19, 2024

Codecov Report

Attention: Patch coverage is 86.00000% with 21 lines in your changes missing coverage. Please review.

Project coverage is 84.01%. Comparing base (a767209) to head (bc46d9d).
Report is 8 commits behind head on next.

Files with missing lines Patch % Lines
src/packages/formitem/formitem.tsx 85.45% 8 Missing ⚠️
src/packages/form/useform.ts 88.70% 7 Missing ⚠️
src/utils/merge.ts 78.94% 4 Missing ⚠️
src/utils/to-array.ts 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #2772      +/-   ##
==========================================
- Coverage   84.07%   84.01%   -0.07%     
==========================================
  Files         217      219       +2     
  Lines       17830    17899      +69     
  Branches     2609     2622      +13     
==========================================
+ Hits        14991    15038      +47     
- Misses       2834     2856      +22     
  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: 6

🧹 Outside diff range and nitpick comments (25)
src/utils/merge.ts (2)

1-2: 建议改进类型定义和参数验证

建议对函数参数和返回值使用更严格的类型定义,并添加空参数校验。

建议按照以下方式修改:

-export function merge(...objects: any[]) {
-  const result: any = Array.isArray(objects[0]) ? [] : {}
+export function merge<T extends object>(...objects: T[]): T {
+  if (objects.length === 0) {
+    throw new Error('至少需要一个参数')
+  }
+  const result = Array.isArray(objects[0]) ? [] : {} as T

26-29: 建议添加性能优化和文档说明

当前实现在处理大量对象或深层嵌套时可能存在性能问题。

建议:

  1. 添加 JSDoc 文档说明函数的使用方式和注意事项
  2. 考虑添加深度限制,避免过深的递归
  3. 可以考虑使用 WeakMap 来优化循环引用检测

示例文档:

/**
 * 深度合并多个对象或数组
 * @param objects - 要合并的对象或数组列表
 * @returns 合并后的对象或数组
 * @throws 当未提供参数时抛出错误
 * @example
 * ```ts
 * merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }
 * merge([1], [2]) // [1, 2]
 * ```
 */
src/packages/textarea/textarea.tsx (1)

Line range hint 1-150: 代码整体结构良好,建议进行小幅优化

组件的实现整体结构清晰,类型定义完整,功能逻辑合理。以下是一些建议:

  1. 考虑将 format 函数抽离为独立的工具函数,以便复用
  2. 可以考虑使用 React.memo 优化性能,因为组件的更新逻辑相对简单

建议重构为:

+ const formatTextAreaValue = (value: string, maxLength: number) => {
+   if (maxLength !== -1 && value.length > maxLength) {
+     return value.substring(0, maxLength)
+   }
+   return value
+ }

- export const TextArea: FunctionComponent<...> = (props) => {
+ export const TextArea: FunctionComponent<...> = React.memo((props) => {
    // ... existing code ...
-   const format = (value: string) => {
-     if (maxLength !== -1 && value.length > maxLength) {
-       return value.substring(0, maxLength)
-     }
-     return value
-   }
+   const format = (value: string) => formatTextAreaValue(value, maxLength)
    // ... rest of the code ...
  })
src/packages/form/doc.md (3)

81-82: 属性文档完善建议

建议补充以下内容:

  1. validateTrigger 属性的具体可选值示例,如 'onChange''onBlur'
  2. disabled 属性对表单项的具体影响说明,包括对验证、提交等操作的影响
-| validateTrigger | 统一设置字段触发验证的时机 | `string` \| `string[]` | `onChange` |
-| disabled | 是否禁用 | `boolean` | `false` |
+| validateTrigger | 统一设置字段触发验证的时机,可选值:'onChange'、'onBlur' 等 | `string` \| `string[]` | `onChange` |
+| disabled | 是否禁用表单,禁用后所有表单项将不可编辑,表单验证和提交操作将被禁止 | `boolean` | `false` |

129-130: API 文档补充建议

建议为新增的 API 添加更详细的使用说明:

  1. setFieldsValue 方法需要补充使用示例,说明对象克隆的场景
  2. setFieldValue 方法需要补充参数类型说明和使用示例
-| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入) | `(values) => void` |
-| setFieldValue | 设置对应字段名的值 | `<T>(name: NamePath, value: T) => void` |
+| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入)。例如:`form.setFieldsValue({ username: 'nutui' })` | `(values: Record<string, any>) => void` |
+| setFieldValue | 设置对应字段名的值。参数:name - 字段名,支持嵌套路径(如 'user.name');value - 字段值。例如:`form.setFieldValue('username', 'nutui')` | `<T>(name: NamePath, value: T) => void` |

文档示例需要补充 disabled 属性的使用说明

检查结果显示:

  1. setFieldValue 方法的使用已在 demo5.tsx 中有完整示例
  2. 缺少 disabled 属性的使用示例,建议补充以下内容:
    • Form 组件级别的禁用
    • Form.Item 组件级别的禁用
🔗 Analysis chain

Line range hint 1-1: 验证文档示例的完整性

请确认是否需要为新增的特性补充相应的示例代码:

  1. disabled 属性的使用示例
  2. setFieldValue 方法的使用示例
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查示例代码中是否包含新特性的使用
rg -l "disabled.*=.*{.*true" "src/packages/form/demos"
rg -l "setFieldValue" "src/packages/form/demos"

Length of output: 217


Script:

#!/bin/bash
# 检查示例代码中是否包含新特性的使用
rg -l "disabled.*=.*true" "src/packages/form/demos"
rg -l "disabled.*:.*true" "src/packages/form/demos"
rg -l "setFieldValue" "src/packages/form/demos"

# 获取demos目录下的所有文件内容以进行更详细的检查
fd . "src/packages/form/demos" -e tsx -x cat {}

Length of output: 26028


Script:

#!/bin/bash
# 检查demo5.tsx中是否包含setFieldValue的使用示例
rg -A 5 "setFieldsValue" "src/packages/form/demos"

# 检查Form组件的disabled属性使用示例
rg -A 2 "disabled.*=.*{" "src/packages/form/demos"
rg -A 2 "disabled:.*" "src/packages/form/demos"

# 检查Form.Item的disabled属性使用示例
rg -A 2 "<Form\.Item.*disabled" "src/packages/form/demos"

Length of output: 1330

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

129-130: 建议补充示例代码

setFieldsValuesetFieldValue 的描述清晰,但建议为这两个方法添加使用示例,以帮助开发者更好地理解它们的区别和正确用法。

示例代码建议:

// setFieldsValue 示例
form.setFieldsValue({
  username: '张三',
  age: 18
});

// setFieldValue 示例
form.setFieldValue('username', '张三');
src/packages/form/doc.taro.md (2)

81-82: 建议为新属性添加使用示例

新增的 validateTriggerdisabled 属性的文档说明清晰,但建议在示例代码部分添加这些属性的具体使用场景和代码示例,以帮助开发者更好地理解如何使用这些新功能。


129-130: 建议补充方法使用说明和示例

  1. setFieldsValue 方法的描述中提到了对象可能被修改的风险,建议补充一个具体的代码示例来说明如何正确克隆对象。

  2. setFieldValue 作为新增方法,建议:

    • 说明与 setFieldsValue 的区别和各自的使用场景
    • 提供实际的使用示例
    • 补充关于嵌套字段的处理说明

建议添加如下示例代码:

// setFieldsValue 示例
const formValues = {
  username: 'nutui',
  address: { city: 'Beijing' }
};
// 错误示例:直接修改对象
form.setFieldsValue(formValues); // formValues 可能被修改

// 正确示例:克隆后传入
form.setFieldsValue({ ...formValues });

// setFieldValue 示例
form.setFieldValue('username', 'nutui');
form.setFieldValue(['address', 'city'], 'Beijing');
src/packages/form/useform.taro.ts (4)

78-80: store更新逻辑集中化,建议考虑添加订阅机制

将store的更新逻辑集中到一个方法中是个很好的重构。不过建议考虑添加订阅机制,以便在store更新时能够更灵活地处理副作用。

  updateStore(nextStore: Store) {
+   const prevStore = this.store
    this.store = nextStore
+   this.notifyStoreChange(prevStore, nextStore)
  }

Line range hint 100-126: 表单字段更新方法的改进很棒,建议加强类型约束

新增的setFieldValue方法和优化后的setFieldsValue方法提供了更灵活的表单更新方式。建议对newStore参数添加更严格的类型约束。

- setFieldsValue = (newStore: any) => {
+ setFieldsValue = (newStore: Partial<Store>) => {

138-142: 验证错误处理改进合理,建议增强警告信息

对缺少name属性的处理很好,但警告信息可以更详细一些,帮助开发者更快定位问题。

- console.warn('Form field missing name property')
+ console.warn('Form field missing name property. This field will be skipped during validation. Please provide a unique name for each form field.')

266-266: 类型断言可以通过泛型优化

当前的类型断言虽然可行,但建议通过泛型来实现更优雅的类型推导。

- return [formRef.current as FormInstance]
+ return [formRef.current!]
src/packages/form/doc.en-US.md (1)

83-84: 属性文档需要补充使用示例

新增的 disabledvalidateTrigger 属性缺少具体的使用示例,建议:

  1. 在文档中添加禁用表单的演示代码
  2. 补充 validateTrigger 支持的具体触发方式(如 onChangeonBlur 等)

建议在文档中添加如下示例:

+### 禁用表单
+
+:::demo
+
+```tsx
+export default () => {
+  return (
+    <Form disabled>
+      <Form.Item label="用户名">
+        <Input placeholder="请输入用户名" />
+      </Form.Item>
+    </Form>
+  )
+}
+```
+
+:::
+
+### 自定义验证触发时机
+
+:::demo
+
+```tsx
+export default () => {
+  return (
+    <Form validateTrigger="onBlur">
+      <Form.Item 
+        label="用户名"
+        rules={[{ required: true, message: '请输入用户名' }]}
+      >
+        <Input placeholder="失去焦点时验证" />
+      </Form.Item>
+    </Form>
+  )
+}
+```
+
+:::
src/packages/form/useform.ts (3)

78-80: 建议添加状态更新回调机制

updateStore 方法可以考虑添加一个回调机制,用于通知外部状态更新完成,这对于异步操作的处理会很有帮助。

-  updateStore(nextStore: Store) {
+  updateStore(nextStore: Store, callback?: () => void) {
     this.store = nextStore
+    callback?.()
   }

122-126: 需要添加单元测试覆盖

setFieldValue 方法缺少单元测试覆盖。建议添加以下测试场景:

  1. 设置单个字段值
  2. 设置嵌套对象的字段值
  3. 验证值更新后的回调触发

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

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 123-126: src/packages/form/useform.ts#L123-L126
Added lines #L123 - L126 were not covered by tests


246-246: 建议完善接口文档

为了提高代码的可维护性,建议:

  1. setFieldValue 方法添加详细的 JSDoc 文档
  2. 补充类型定义中的参数说明
  3. 添加使用示例
+  /**
+   * 设置表单字段的值
+   * @param name 字段名称
+   * @param value 字段值
+   * @example
+   * form.setFieldValue('username', '张三')
+   * form.setFieldValue('address.city', '北京')
+   */
   setFieldValue: this.setFieldValue,

Also applies to: 266-266

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

Line range hint 78-92: 表单实例访问方式的改进建议

代码重构提升了封装性,但建议增加以下改进:

  1. 建议为 store 添加具体的类型定义,避免使用 any
  2. 考虑添加空值检查,确保 formInstance 存在
- const { store = {}, setInitialValues } =
-   this.context.formInstance.getInternal(SECRET)
+ type Store = Record<string, any>  // TODO: 使用更具体的类型
+ const { store = {} as Store, setInitialValues } =
+   this.context.formInstance?.getInternal(SECRET) ?? {}

195-200: 建议优化类名处理方法

  1. 建议添加测试用例覆盖不同 labelPosition 的场景
  2. 考虑使用类名工具库(如 classnames)优化类名拼接
  3. 建议添加类型检查确保 labelPosition 值的合法性
+ type LabelPosition = 'left' | 'top' | undefined

  getClassNameWithDirection(className: string) {
-   if (className && this.context.labelPosition) {
+   const position = this.context.labelPosition as LabelPosition
+   if (className && position) {
-     return `${className} ${className}-${this.context.labelPosition}`
+     return `${className} ${className}-${position}`
    }
    return className
  }
🧰 Tools
🪛 GitHub Check: codecov/patch

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


220-249: 建议增强布局渲染的类型安全性和可访问性

  1. 建议为 starPosition 添加明确的类型定义
  2. 考虑添加 ARIA 属性以提升表单的可访问性
  3. 建议使用常量定义类名前缀,避免硬编码
+ const CLASS_PREFIX = 'nut-form-item'
+ type StarPosition = 'left' | 'right'
+ interface FormInstance {
+   starPosition: StarPosition;
+   // ... other properties
+ }

- const { starPosition } = this.context.formInstance
+ const { starPosition } = this.context.formInstance as FormInstance

  return (
    <Cell
-     className={`${this.getClassNameWithDirection('nut-form-item')} ${className}`}
+     className={`${this.getClassNameWithDirection(CLASS_PREFIX)} ${className}`}
+     role="group"
+     aria-labelledby={`${name}-label`}
    >
🧰 Tools
🪛 Biome

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

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

当前的验证触发器实现逻辑清晰,但建议添加以下改进:

  1. 对 trigger 回调函数的执行增加错误处理
  2. 验证规则为空时避免不必要的 dispatch 调用

建议的改进代码:

 validateTriggers.forEach((trigger) => {
   const originTrigger = controlled[trigger]
   controlled[trigger] = (...args: any) => {
+    try {
       if (originTrigger) {
         originTrigger(...args)
       }
-      if (this.props.rules && this.props.rules.length) {
+      if (this.props.rules?.length > 0) {
         dispatch({
           name: this.props.name,
         })
       }
+    } catch (error) {
+      console.error('验证触发器执行失败:', error)
+    }
   }
 })

281-284: 建议增强禁用状态的可访问性

当前禁用状态的实现可以通过添加 ARIA 属性来提高可访问性。

建议的改进代码:

 <View
   className={this.context.disabled ? 'nut-form-item-disabled' : ''}
   catchMove={this.context.disabled}
+  aria-disabled={this.context.disabled}
+  role="group"
 >

115-120: 建议改进开发环境警告信息

当前的警告信息可以更加详细,帮助开发者更好地理解和修复问题。

建议的改进代码:

 if (process.env.NODE_ENV !== 'production') {
   console.warn(
-    '[NutUI] FormItem:',
-    '请通过 initialValue 设置初始值,而不是 defaultValue'
+    '[NutUI] FormItem 警告:',
+    `组件 "${name || '未命名'}" 使用了 defaultValue 进行初始化。`,
+    '为了保持一致性和更好的表单控制,请使用 initialValue 属性来设置初始值。',
+    '\n相关文档:<文档链接>'
   )
 }
src/packages/form/__tests__/form.spec.tsx (2)

Line range hint 89-134: 建议增加更多验证触发器的测试用例

当前测试用例仅覆盖了 onBlur 触发验证的场景。为了确保完整的功能覆盖,建议添加以下测试场景:

  • onChange 触发验证
  • onSubmit 触发验证
  • 多个触发器组合的场景

建议添加如下测试用例:

test('form validateTrigger with onChange', async () => {
  const { container } = render(
    <Form>
      <Form.Item
        name="username"
        validateTrigger="onChange"
        rules={[{ required: true }]}
      >
        <Input />
      </Form.Item>
    </Form>
  )
  const input = container.querySelector('.nut-input-native')
  if (input) {
    fireEvent.change(input, { target: { value: '' } })
    await waitFor(() => {
      const errorMessage = container.querySelector('.nut-form-item-body-tips')
      expect(errorMessage).toBeTruthy()
    })
  }
})

Line range hint 135-169: 缺少新增 setFieldValue 方法的测试用例

根据 PR 目标,新增了 setFieldValue 方法,但测试文件中缺少对应的测试用例。建议添加以下测试场景:

  • 单个字段值设置
  • 错误处理场景
  • 值更新后的表单验证

建议添加如下测试用例:

test('form setFieldValue', async () => {
  const [form] = Form.useForm()
  const { container } = render(
    <Form form={form}>
      <Form.Item name="username">
        <Input />
      </Form.Item>
    </Form>
  )
  
  await form.setFieldValue('username', 'test')
  expect(container.querySelector('.nut-input-native')).toHaveValue('test')
  
  // 测试不存在的字段
  await expect(form.setFieldValue('nonexistent', 'test')).rejects.toThrow()
})
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6ee015e and c77223c.

📒 Files selected for processing (12)
  • src/packages/form/__tests__/form.spec.tsx (2 hunks)
  • 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/useform.taro.ts (7 hunks)
  • src/packages/form/useform.ts (7 hunks)
  • src/packages/formitem/formitem.taro.tsx (8 hunks)
  • src/packages/formitem/formitem.tsx (8 hunks)
  • src/packages/textarea/textarea.taro.tsx (0 hunks)
  • src/packages/textarea/textarea.tsx (1 hunks)
  • src/utils/merge.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/packages/textarea/textarea.taro.tsx
🧰 Additional context used
🪛 GitHub Check: codecov/patch
src/packages/form/useform.ts

[warning] 123-126: src/packages/form/useform.ts#L123-L126
Added lines #L123 - L126 were not covered by tests


[warning] 140-142: src/packages/form/useform.ts#L140-L142
Added lines #L140 - L142 were not covered by tests

src/packages/formitem/formitem.tsx

[warning] 114-119: src/packages/formitem/formitem.tsx#L114-L119
Added lines #L114 - L119 were not covered by tests


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


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

src/utils/merge.ts

[warning] 10-10: src/utils/merge.ts#L10
Added line #L10 was not covered by tests


[warning] 14-14: src/utils/merge.ts#L14
Added line #L14 was not covered by tests


[warning] 17-18: src/utils/merge.ts#L17-L18
Added lines #L17 - L18 were not covered by tests

🪛 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)

🔇 Additional comments (10)
src/utils/merge.ts (1)

4-24: ⚠️ Potential issue

需要补充测试用例并优化实现

  1. 测试覆盖率不足,特别是数组处理和循环引用检测的场景
  2. 建议优化循环引用检测的实现方式

请运行以下脚本检查现有的测试用例:

建议添加以下测试场景:

  1. 数组合并
  2. 循环引用处理
  3. 深层对象合并
  4. 空值处理

另外建议优化实现:

-        if (path.some((p: any) => p === value)) continue
+        const circularRef = path.includes(value)
+        if (circularRef) {
+          console.warn(`检测到循环引用: ${newPath.join('.')}`)
+          continue
+        }
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 10-10: src/utils/merge.ts#L10
Added line #L10 was not covered by tests


[warning] 14-14: src/utils/merge.ts#L14
Added line #L14 was not covered by tests


[warning] 17-18: src/utils/merge.ts#L17-L18
Added lines #L17 - L18 were not covered by tests

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

82-83: 属性文档描述清晰且完整

新增的 validateTriggerdisabled 属性的文档说明简洁明了,参数类型定义准确。

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

3-3: 类型定义和工具函数导入看起来不错!

新增的类型定义和merge工具函数的导入增强了代码的类型安全性和状态管理的一致性。

Also applies to: 7-7, 9-9


88-92: 初始值设置逻辑优化得很好!

使用merge工具函数来处理初始值的设置,避免了直接覆盖现有状态,同时参数命名的修改也提高了代码的可读性。

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

130-131: 建议完善 setFieldValue 的文档说明

该评论已在之前的审查中提出,仍然有效。建议按照之前的建议完善文档:

  1. 补充方法的具体用途和使用场景
  2. 添加与 setFieldsValue 的区别说明
  3. 提供实际使用的代码示例
src/packages/form/useform.ts (1)

3-3: 验证 merge 函数的深度合并实现

根据之前的代码评审意见,需要确保 merge 函数能够正确处理嵌套对象的合并。建议:

  1. 验证 merge 函数是否支持深度合并
  2. 考虑使用 lodash 的 merge 或实现自定义的深度合并函数

Also applies to: 7-7, 9-9

✅ Verification successful

Let me gather more information about the merge implementation to provide a complete verification.


merge 函数实现已验证,无需更改

经过验证,当前的 merge 函数实现已经包含了以下特性:

  • 支持深度递归合并对象
  • 正确处理数组覆盖
  • 包含循环引用检测
  • 在 useform.ts 中的使用场景(初始化、更新、重置)都是合适的

该实现完全满足表单状态管理的需求,无需切换到 lodash 的 merge 实现。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:检查merge函数实现
rg "export.*merge" src/utils/merge.ts -A 10

Length of output: 466


Script:

#!/bin/bash
# Get the complete merge function implementation
rg "export.*merge" src/utils/merge.ts -A 20

# Find usages of merge in useform.ts to understand the context
rg "merge\(" src/packages/form/useform.ts -A 2

Length of output: 1246

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

2-2: 导入更改看起来不错!

新增的导入支持了组件从 div 到 Taro 组件的迁移,以及 validateTrigger 的数组处理功能。

Also applies to: 8-8


79-80: 避免使用内部方法 getInternal(SECRET)

这个问题在之前的代码评审中已经提出,但仍未解决。建议重构这部分代码以使用公开的 API。

Also applies to: 92-93

src/packages/form/__tests__/form.spec.tsx (2)

3-4: 导入语句重新排序,代码更加整洁

导入语句的重新排序提高了代码的可读性,保持了一致的导入顺序。


170-172: 类名更新符合组件命名规范

将必填字段的类名从 '.required' 更新为 '.nut-form-item-label-required',更符合组件的命名规范,提高了类名的特异性。

src/packages/textarea/textarea.tsx Outdated Show resolved Hide resolved
src/packages/form/doc.zh-TW.md Outdated Show resolved Hide resolved
src/packages/form/useform.ts Show resolved Hide resolved
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: 0

🧹 Outside diff range and nitpick comments (2)
src/packages/form/doc.zh-TW.md (2)

129-129: 建議補充說明物件複製的具體示例

為了幫助開發者更好地理解,建議添加一個具體的代碼示例來說明如何安全地複製物件:

// 不推薦
form.setFieldsValue(someObject);

// 推薦
form.setFieldsValue({...someObject});
// 或
form.setFieldsValue(JSON.parse(JSON.stringify(someObject)));

130-130: 建議補充 setFieldValue 使用場景說明

建議補充說明該方法與 setFieldsValue 的區別和適用場景,例如:

  • setFieldValue 適用於單個欄位更新
  • 相比 setFieldsValue 更容易避免非預期的欄位修改
  • 可以提供一個簡單的使用示例
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c77223c and bc8a8aa.

📒 Files selected for processing (2)
  • src/packages/form/doc.zh-TW.md (3 hunks)
  • src/packages/textarea/textarea.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • src/packages/textarea/textarea.tsx
🔇 Additional comments (1)
src/packages/form/doc.zh-TW.md (1)

82-83: 需要將 validateTrigger 描述改為繁體中文

建議將描述文字從"統一設定字段觸發驗證的時機"修改為"統一設定欄位觸發驗證的時機",以保持繁體中文的一致性。

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.scss (2)

4-6: 建议使用 CSS 变量来控制禁用状态的透明度

建议将固定的透明度值改为可配置的 CSS 变量,以提供更好的主题定制能力。

  &-disabled {
-   opacity: 0.4;
+   opacity: var(--nut-form-disabled-opacity, 0.4);
    pointer-events: none;
  }

114-148: 建议统一使用 CSS 变量管理间距值

当前的间距值(24px, 12px, 4px)直接硬编码在样式中,建议抽取为可复用的 CSS 变量。

+ :root {
+   --nut-form-spacing-lg: 24px;
+   --nut-form-spacing-md: 12px;
+   --nut-form-spacing-sm: 4px;
+ }

  .nut-form-item-label-right {
    justify-content: flex-end;
-   padding-right: 24px;
+   padding-right: var(--nut-form-spacing-lg);
    white-space: nowrap;
  }
src/packages/formitem/formitem.tsx (5)

78-79: 建议重构内部方法的访问方式

当前实现通过 SECRET 访问内部方法可能会暴露实现细节,建议考虑以下方案:

  • 将这些方法直接暴露在 formInstance 接口中
  • 或者创建专门的内部接口来处理这些操作
-const { store = {}, setInitialValues } = this.context.formInstance.getInternal(SECRET)
+const { store = {}, setInitialValues } = this.context.formInstance

-const { registerField, registerUpdate } = this.context.formInstance.getInternal(SECRET)
+const { registerField, registerUpdate } = this.context.formInstance

Also applies to: 91-92


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

getClassNameWithDirection 方法在每次渲染时都会重新计算类名。建议:

  • 使用 useMemo 或类组件的实例属性来缓存结果
  • 只在 labelPosition 改变时重新计算
+private cachedClassNames: Map<string, string> = new Map()

 getClassNameWithDirection(className: string) {
+  const cacheKey = `${className}-${this.context.labelPosition}`
+  if (this.cachedClassNames.has(cacheKey)) {
+    return this.cachedClassNames.get(cacheKey)
+  }
   if (className && this.context.labelPosition) {
-    return `${className} ${className}-${this.context.labelPosition}`
+    const result = `${className} ${className}-${this.context.labelPosition}`
+    this.cachedClassNames.set(cacheKey, result)
+    return result
   }
   return className
 }
🧰 Tools
🪛 GitHub Check: codecov/patch

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


220-229: 建议增强必填标记的可访问性

当前必填标记的实现可以通过以下方式增强可访问性:

  • 添加 aria-required 属性
  • 为屏幕阅读器提供更好的提示信息
 const renderStar = (required || requiredInRules) && (
-  <div className="nut-form-item-label-required required">*</div>
+  <div 
+    className="nut-form-item-label-required required"
+    aria-hidden="true"
+  >*</div>
 )
 const renderLabel = (
   <>
-    <span className="nut-form-item-labeltxt">
+    <span 
+      className="nut-form-item-labeltxt"
+      aria-required={required || requiredInRules}
+    >

243-251: 建议使用可选链操作符优化代码

当前的类名拼接可以通过使用可选链操作符来简化:

-<div
-  className={`nut-cell-title ${this.getClassNameWithDirection('nut-form-item-label')}`}
->
+<div
+  className={`nut-cell-title ${this.getClassNameWithDirection('nut-form-item-label')}`}
+>
🧰 Tools
🪛 Biome

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


建议为 FormItem 组件添加独立的测试文件和完整的测试用例

目前 FormItem 组件缺少独立的测试文件,仅在 Form 组件的测试中有少量涉及。建议参考 Input 组件的测试结构,为 FormItem 创建专门的测试文件,覆盖以下场景:

  • 基础渲染和属性验证
  • 禁用状态的交互测试
  • 验证触发器(validateTrigger)的多种组合场景
  • noStyle 属性的渲染测试
  • 类名生成逻辑
  • 错误信息展示
  • 表单项重置功能

建议在 src/packages/formitem/__test__/formitem.spec.tsx 中实现这些测试用例。

🔗 Analysis chain

Line range hint 1-289: 建议增加测试覆盖率

当前实现缺少以下场景的测试覆盖:

  • 禁用状态的交互测试
  • 验证触发器的多种组合场景
  • noStyle 属性的渲染测试
  • 类名生成的单元测试
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查当前的测试覆盖情况
fd -t f "formitem.*\.(test|spec)\.(tsx|ts)" src/packages/formitem/

# 检查现有的测试用例
rg "describe|it|test" -A 3 src/packages/formitem/**/*test*

Length of output: 203


Script:

#!/bin/bash
# 检查是否存在任何测试文件
fd -t f ".*\.(test|spec)\.(tsx|ts|js|jsx)" src/packages/formitem/

# 检查整个仓库中是否有针对FormItem的测试
rg -g "*.test.*" -g "*.spec.*" "FormItem" -A 3 src/

# 检查是否有其他组件的测试文件作为参考
fd -t f ".*\.(test|spec)\.(tsx|ts|js|jsx)" src/packages/

Length of output: 7495


Script:

#!/bin/bash
# 检查Form组件测试文件中关于FormItem的测试用例
rg "FormItem" -B 2 -A 5 src/packages/form/__tests__/form.spec.tsx

# 检查其他组件的测试文件结构作为参考
cat src/packages/input/__test__/input.spec.tsx

Length of output: 5967

🧰 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 (5)

115-120: 控制台警告实现得当!

在开发环境下提醒开发者使用 initialValue 而不是 defaultValue 是个好做法。不过建议考虑:

  1. 将警告信息提取到常量中,便于维护
  2. 考虑添加文档链接,帮助开发者理解原因
+ const WARNINGS = {
+   defaultValue: '[NutUI] FormItem: 请通过 initialValue 设置初始值,而不是 defaultValue。详情请参考:<doc_url>'
+ }

  if (process.env.NODE_ENV !== 'production') {
-   console.warn(
-     '[NutUI] FormItem:',
-     '请通过 initialValue 设置初始值,而不是 defaultValue'
-   )
+   console.warn(WARNINGS.defaultValue)
  }

145-161: 验证触发器实现可以优化!

当前实现在每次渲染时都会重新创建验证函数。建议:

  1. 使用 useMemo 或类组件等价方式缓存验证函数
  2. 考虑将验证逻辑提取到单独的方法中
+ private createValidationHandler = (trigger: string, originTrigger: Function) => {
+   return (...args: any) => {
+     if (originTrigger) {
+       originTrigger(...args)
+     }
+     if (this.props.rules?.length) {
+       this.context.formInstance.getInternal(SECRET).dispatch({
+         name: this.props.name,
+       })
+     }
+   }
+ }

  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,
-       })
-     }
-   }
+   controlled[trigger] = this.createValidationHandler(trigger, originTrigger)
  })

223-230: 建议增强标签的可访问性!

当前实现使用了 Taro 的 Text 组件,但可以通过以下方式提升可访问性:

  1. 为必填标记添加 aria-hidden="true"
  2. 使用 aria-required="true" 标记必填字段
  3. 确保标签与表单控件的关联
- <Text className="nut-form-item-label-required required">*</Text>
+ <Text 
+   className="nut-form-item-label-required required"
+   aria-hidden="true"
+ >*</Text>

- <Text className="nut-form-item-labeltxt">
+ <Text 
+   className="nut-form-item-labeltxt"
+   aria-required={required || requiredInRules}
+ >

283-290: 建议增强禁用状态的类型安全性!

当前实现正确处理了禁用状态,但可以通过以下方式改进:

  1. 为 context 中的 disabled 添加明确的类型定义
  2. 考虑使用常量定义类名
  3. 添加禁用状态的样式类型定义
+ const FORM_ITEM_CLASSES = {
+   disabled: 'nut-form-item-disabled'
+ } as const

- className={this.context.disabled ? 'nut-form-item-disabled' : ''}
+ className={this.context.disabled ? FORM_ITEM_CLASSES.disabled : ''}

254-262: 建议优化错误消息的样式处理!

当前实现使用内联样式控制错误消息显示,建议:

  1. 使用 CSS 类替代内联样式
  2. 使用 CSS 变量处理文本对齐
  3. 考虑使用 CSS 动画优化显示/隐藏过渡
+ // 在样式文件中
+ .nut-form-item-body-tips {
+   display: none;
+   text-align: var(--nut-form-error-align, left);
+   transition: opacity 0.2s;
+ }
+ 
+ .nut-form-item-body-tips.visible {
+   display: block;
+ }

- style={{
-   textAlign: errorMessageAlign,
-   display: item?.length ? 'initial' : 'none',
- }}
+ className={`nut-form-item-body-tips ${item?.length ? 'visible' : ''}`}
+ style={{
+   '--nut-form-error-align': errorMessageAlign
+ } as React.CSSProperties}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between bc8a8aa and 41da784.

📒 Files selected for processing (3)
  • src/packages/formitem/formitem.scss (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (8 hunks)
  • src/packages/formitem/formitem.tsx (8 hunks)
🧰 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)

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

[warning] 114-119: src/packages/formitem/formitem.tsx#L114-L119
Added lines #L114 - L119 were not covered by tests


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


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

🔇 Additional comments (2)
src/packages/formitem/formitem.scss (1)

150-179: RTL 支持实现完善

RTL(从右到左)布局的支持实现得很完善,正确处理了方向性属性,并保持了一致的间距控制。

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

2-2: 导入更改看起来不错!

新增的导入符合 Taro 组件系统的要求,同时添加了必要的工具函数。

Also applies to: 8-8

src/packages/formitem/formitem.scss Show resolved Hide resolved
src/packages/formitem/formitem.tsx Show resolved Hide resolved
src/packages/formitem/formitem.tsx Show resolved Hide resolved
@oasis-cloud oasis-cloud requested a review from irisSong December 5, 2024 09:09
Copy link
Collaborator

@irisSong irisSong left a comment

Choose a reason for hiding this comment

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

升级文档更新

divider: boolean
validateTrigger: string | string[] | false
Copy link
Collaborator

Choose a reason for hiding this comment

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

文档是两个类型,不一致

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: 0

🧹 Outside diff range and nitpick comments (4)
src/packages/form/doc.zh-TW.md (2)

82-83: 建议完善属性说明

建议补充以下内容:

  1. validateTrigger 属性的具体使用场景和示例
  2. disabled 属性对表单项的具体影响说明
-| validateTrigger | 統一設定字段觸發驗證的時機 | `string` \| `string[]`\| `false` | `onChange` |
+| validateTrigger | 統一設定字段觸發驗證的時機。可設置為 `onBlur` 或 `['onChange', 'onBlur']` 等。設置為 `false` 時關閉自動驗證 | `string` \| `string[]`\| `false` | `onChange` |
-| disabled | 是否禁用 | `boolean` | `false` |
+| disabled | 是否禁用表單。當設置為 `true` 時,表單內所有輸入框、按鈕等交互元素將被禁用 | `boolean` | `false` |

129-130: 建议完善 setFieldValue 方法说明

当前 setFieldValue 的描述过于简单,建议补充以下内容:

  1. 使用场景说明
  2. setFieldsValue 的区别
  3. 代码示例
 | setFieldsValue | 設定表單的值(該值將直接傳入 form store 中。如果你不希望傳入物件被修改,請複製後傳入) | `(values) => void` |
-| setFieldValue | 設定對應欄位名的值 | `<T>(name: NamePath, value: T) => void` |
+| setFieldValue | 設定對應欄位名的值。用於單個字段更新場景,支持嵌套路徑設置。例如:
+```tsx
+// 設置簡單字段
+form.setFieldValue('username', 'newValue');
+
+// 設置嵌套字段
+form.setFieldValue(['user', 'address', 'city'], 'Taipei');
+``` | `<T>(name: NamePath, value: T) => void` |
src/packages/form/doc.en-US.md (2)

83-84: 建议完善英文属性说明

建议补充以下内容:

  1. validateTrigger 属性的详细说明和示例
  2. disabled 属性的具体影响说明
-| disabled | Disable all form fields | `boolean` | `false` |
+| disabled | Disable all form fields. When set to `true`, all interactive elements within the form (inputs, buttons, etc.) will be disabled | `boolean` | `false` |
-| validateTrigger | uniformly set the timing for fields to trigger validation | `string` \| `string[]`\| `false` | `onChange` |
+| validateTrigger | Uniformly set the timing for fields to trigger validation. Can be set to `onBlur` or `['onChange', 'onBlur']`. Set to `false` to disable automatic validation | `string` \| `string[]`\| `false` | `onChange` |

130-131: 建议完善英文方法说明

建议补充 setFieldValue 方法的以下内容:

  1. 使用场景说明
  2. setFieldsValue 的区别
  3. 代码示例
 | setFieldsValue | Set the value of the form (the value will be passed directly to the form store. If you do not want the object passed in to be modified, please copy it and pass it in) | `(values) => void` |
-| setFieldValue | Set the value of the corresponding field name | `<T>(name: NamePath, value: T) => void` |
+| setFieldValue | Set the value of the corresponding field name. Used for single field updates, supports nested path setting. Example:
+```tsx
+// Set simple field
+form.setFieldValue('username', 'newValue');
+
+// Set nested field
+form.setFieldValue(['user', 'address', 'city'], 'New York');
+``` | `<T>(name: NamePath, value: T) => void` |
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 41da784 and bc46d9d.

📒 Files selected for processing (4)
  • 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 (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/packages/form/doc.md
🔇 Additional comments (2)
src/packages/form/doc.taro.md (2)

81-82: 建议完善属性说明


129-130: 建议完善 setFieldValue 方法说明

@oasis-cloud oasis-cloud merged commit 5588ad4 into jdf2e:next Dec 6, 2024
6 checks passed
This was referenced Dec 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment