Skip to content

Conversation

@mynetfan
Copy link
Collaborator

@mynetfan mynetfan commented Mar 9, 2025

Description

  • 改进表单API以支持组件实例的获取。可以根据字段名获取表单中的组件实例,用来调用组件暴露的方法。
  • 改进组件适配器里的组件包装函数,透传组件暴露的方法
  • 表单API新增获取当前焦点组件的方法:该方法将返回表单组件(或者其子组件)拥有焦点的字段名。VeeValidate自定义校验函数无法设置仅在失去焦点时才调用,该方法可用于支持在自定义的异步校验函数中判断当前字段是否已失去焦点以避免input组件在输入文字时反复调用校验函数。

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.

Checklist

ℹ️ Check all checkboxes - this will indicate that you have done everything in accordance with the rules in CONTRIBUTING.

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs:dev command.
  • Run the tests with pnpm test.
  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • New Features

    • Enhanced form components now support more flexible placeholder management and expose additional methods for field reference handling.
    • The form API now allows retrieval of specific field component references and identification of the currently focused field.
    • The login experience has been improved with automatic captcha refresh on failed attempts.
    • A new control in form examples enables direct focus management for dropdown components.
  • Documentation

    • Updated form API documentation now details the new utility methods and their version history.
  • Chores

    • Upgraded dependency and package manager versions for improved performance and reliability.

@mynetfan mynetfan requested review from a team, anncwb and vince292007 as code owners March 9, 2025 18:44
@changeset-bot
Copy link

changeset-bot bot commented Mar 9, 2025

⚠️ No Changeset found

Latest commit: ed0c2dc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2025

Walkthrough

This PR introduces multiple refactors and feature enhancements across several modules. The primary changes refactor the withDefaultPlaceholder function into a Vue component using defineComponent, enhancing placeholder management and exposing component methods via a public API. In addition, the PR updates documentation for the form API, augments the FormApi class and related components to manage component references, revises the login component’s submission logic, updates dependency versions, and improves form field focus handling.

Changes

Files Change Summary
apps/web-antd/src/adapter/component/index.ts, apps/web-ele/src/adapter/component/index.ts, apps/web-naive/src/adapter/component/index.ts, playground/src/adapter/component/index.ts Refactored withDefaultPlaceholder to use defineComponent; enhanced placeholder checking from props and attrs; introduced innerRef and a public API; updated return types.
docs/src/components/common-ui/vben-form.md Updated documentation for useVbenForm by adding new methods (getFieldComponentRef and getFocusedField) and a version column in method tables.
package.json, pnpm-workspace.yaml Updated package management: bumped pnpm version in package.json and updated various dependency versions in pnpm-workspace.yaml.
packages/@core/ui-kit/form-ui/src/form-api.ts, packages/@core/ui-kit/form-ui/src/form-render/form-field.vue, packages/@core/ui-kit/form-ui/src/use-form-context.ts, packages/@core/ui-kit/form-ui/src/vben-use-form.vue Introduced a componentRefMap in FormApi; added getFieldComponentRef and getFocusedField methods; implemented context management with injectComponentRefMap/provideComponentRefMap; updated form-field and vben-use-form for proper registration and cleanup of component references.
playground/src/views/_core/authentication/login.vue, playground/src/views/examples/form/api.vue Added a new login submission handler using useTemplateRef with error handling and captcha reset, and introduced a new 'componentRef' action in form example to focus a dropdown component.

Sequence Diagram(s)

sequenceDiagram
    participant Parent
    participant Wrapper as withDefaultPlaceholder
    participant Setup as Setup Function
    participant Vue as Vue Lifecycle ($nextTick)
    participant API as Public API

    Parent->>Wrapper: Call withDefaultPlaceholder(component, type)
    Wrapper->>Setup: Initialize component via defineComponent
    Setup->>Setup: Create innerRef for component instance
    Setup->>Vue: Retrieve current instance & register $nextTick callback
    Vue-->>Setup: Execute callback post-mount
    Setup->>API: Populate public API with innerRef methods
    Setup-->>Parent: Return enhanced component with public API
Loading
sequenceDiagram
    participant Field as Form Field Component
    participant Context as ComponentRefMap (via inject/provide)
    participant FormAPI as FormApi

    Field->>Context: Register field reference (via watch)
    Field->>Context: On unmount, remove field reference (onUnmounted)
    FormAPI->>Context: Lookup field reference via getFieldComponentRef
    Context-->>FormAPI: Return component instance (if focused)
Loading

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • vince292007
  • anncwb

Poem

I'm a bunny coder, hopping through the code,
Refactoring functions on a bright, green road.
With placeholders and refs, our code does gleam,
New methods and APIs dancing like a dream.
Crunching bugs with carrots, in style so neat,
Celebrating changes with a joyful, little beat!
🐰🥕 Happy coding!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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 generate docstrings to generate docstrings for this 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
Contributor

@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

🧹 Nitpick comments (5)
playground/src/views/_core/authentication/login.vue (1)

111-121: Verify the async usage and consider a more consistent error-handling approach.

Currently, the function is marked async but uses a .catch() on the promise instead of try/catch. You may either remove async or use an explicit await/try-catch to handle errors more uniformly.

apps/web-antd/src/adapter/component/index.ts (1)

45-68: Refactored component wrapper looks good but watch for timing issues.

The pattern of capturing child methods on nextTick is effective for exposing the underlying API, though there's a brief window before those methods are assigned to publicApi. If immediate parent usage is necessary, consider verifying that parent calls happen after the nextTick lifecycle. Otherwise, this approach is a clean way to forward methods from the wrapped component.

playground/src/adapter/component/index.ts (1)

45-68: Consider adding type safety and ref null checks.
While the pattern of exposing the child component’s methods is valid, relying on any props and iterating over innerRef.value without null checks can lead to runtime errors or type mismatches in certain edge cases.

Below is an optional improvement:

  1. Replace props: any with a proper props type or generics to ensure type safety.
  2. Safeguard usage of innerRef.value with optional chaining or an existence check:
-        for (const key in innerRef.value) {
-          if (typeof innerRef.value[key] === 'function') {
-            publicApi[key] = innerRef.value[key];
-          }
-        }
+        const inner = innerRef.value;
+        if (inner) {
+          for (const key in inner) {
+            if (typeof inner[key] === 'function') {
+              publicApi[key] = inner[key];
+            }
+          }
+        }

Consider architectural unification.
You have repeated versions of withDefaultPlaceholder across multiple files (playground, web-ele, web-naive). Factor them out into a shared utility to promote DRY and consistent maintenance if possible.

apps/web-ele/src/adapter/component/index.ts (1)

41-64: Enhance type definitions and avoid potential null references.
Currently, props is typed as any, and innerRef.value might be undefined at render time. For added resilience and clarity:

  1. Define a more explicit props interface if feasible.
  2. Use defensively optional chaining when iterating methods from innerRef.value to prevent crashes.
-        for (const key in innerRef.value) {
-          if (typeof innerRef.value[key] === 'function') {
-            publicApi[key] = innerRef.value[key];
-          }
-        }
+        const inner = innerRef.value;
+        if (inner) {
+          for (const key in inner) {
+            if (typeof inner[key] === 'function') {
+              publicApi[key] = inner[key];
+            }
+          }
+        }

Reduce duplication across adapters.
Since an almost identical withDefaultPlaceholder is used across multiple adapters (web-antd, web-naive, etc.), consider centralizing this logic in a shared module.

apps/web-naive/src/adapter/component/index.ts (1)

41-64: Improve null safety and unify the pattern.
To ensure stability and maintainability:

  1. Add a quick null check for innerRef.value to avoid unexpected runtime errors.
  2. Encourage a typed props structure rather than props: any.
  3. Factor out the withDefaultPlaceholder logic into a shared file to reduce duplication across multiple adapters.
-        for (const key in innerRef.value) {
-          if (typeof innerRef.value[key] === 'function') {
-            publicApi[key] = innerRef.value[key];
-          }
-        }
+        const inner = innerRef.value;
+        if (inner) {
+          for (const key in inner) {
+            if (typeof inner[key] === 'function') {
+              publicApi[key] = inner[key];
+            }
+          }
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb68380 and ed0c2dc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • apps/web-antd/src/adapter/component/index.ts (2 hunks)
  • apps/web-ele/src/adapter/component/index.ts (2 hunks)
  • apps/web-naive/src/adapter/component/index.ts (2 hunks)
  • docs/src/components/common-ui/vben-form.md (1 hunks)
  • package.json (1 hunks)
  • packages/@core/ui-kit/form-ui/src/form-api.ts (4 hunks)
  • packages/@core/ui-kit/form-ui/src/form-render/form-field.vue (3 hunks)
  • packages/@core/ui-kit/form-ui/src/use-form-context.ts (1 hunks)
  • packages/@core/ui-kit/form-ui/src/vben-use-form.vue (2 hunks)
  • playground/src/adapter/component/index.ts (2 hunks)
  • playground/src/views/_core/authentication/login.vue (2 hunks)
  • playground/src/views/examples/form/api.vue (5 hunks)
  • pnpm-workspace.yaml (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: Lint (ubuntu-latest)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: post-update (windows-latest)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: Check (ubuntu-latest)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (28)
package.json (1)

102-102: Package manager version updated.

The package manager version has been updated from 9.15.6 to 9.15.7. This is likely a routine maintenance update that includes bug fixes or minor enhancements.

packages/@core/ui-kit/form-ui/src/vben-use-form.vue (4)

20-24: Import updated to include component reference map provider.

The import statement has been updated to include provideComponentRefMap, which is used to provide the component reference map to child components.


36-37: Component reference map initialization.

A new Map is initialized to store component references by field name. This is a key part of the new feature allowing component instances to be retrieved.


41-41: Providing component reference map to descendant components.

The component reference map is provided to the component tree using Vue's dependency injection system, making it accessible to field components.


43-43: Passing component reference map to FormApi.

The component reference map is now passed to the FormApi's mount method, enabling the API to access component instances by field name.

packages/@core/ui-kit/form-ui/src/use-form-context.ts (1)

23-24: New context for component reference management.

Added context functions for injecting and providing a map of component references, which enables component instance retrieval throughout the form component tree.

packages/@core/ui-kit/form-ui/src/form-render/form-field.vue (3)

6-6: Added onUnmounted lifecycle hook import.

The onUnmounted hook is now imported to support proper cleanup of component references when fields are removed.


21-21: Added import for component reference map injection.

Importing the injectComponentRefMap function to access the component reference map provided by the parent form.


271-279: Component reference tracking implementation.

This code adds crucial functionality to track field component references:

  1. It injects the component reference map from the form context
  2. It watches for changes to the field component reference and updates the map
  3. It cleans up references when components are unmounted to prevent memory leaks

This implementation is essential for the new feature that allows retrieving component instances by field name.

docs/src/components/common-ui/vben-form.md (1)

282-299: Good documentation coverage for newly introduced methods.

The added rows effectively communicate the usage and availability of getFieldComponentRef and getFocusedField. This section clearly aligns with the updated form API functionalities and helps developers understand how to interact with component instances and focus management within forms.

playground/src/views/_core/authentication/login.vue (2)

3-5: No issues found with new imports.

Importing Recordable and useTemplateRef is clear and helps maintain type safety while exposing component references.


108-110: Appropriate usage of template ref for authentication component.

Storing a reference to the AuthenticationLogin component instance allows for easier calling of methods like getFormApi.

playground/src/views/examples/form/api.vue (1)

2-3: Neat addition of component reference handling and focus control.

• The extended action union for 'componentRef' fits seamlessly into the existing structure.
• Retrieving the dropdown’s component instance and calling focus() showcases getFieldComponentRef effectively.
• The new button for testing this interaction is a practical demo entry point.

Also applies to: 83-87, 135-139, 268-268

playground/src/adapter/component/index.ts (3)

6-6: Import of Component is correct.
The import from 'vue' aligns well with the upcoming usage of defineComponent.


9-9: Import of Recordable is correct.
This type import is valid for storing the methods in a dictionary-like object.


11-11: Imports for Vue composition API are correct.
Using defineComponent, getCurrentInstance, h, and ref is appropriate for this refactor.

apps/web-ele/src/adapter/component/index.ts (2)

6-6: Import of Component is correct.
No issues found with the import from 'vue'.


11-11: Imports for Vue composition API are valid.
The usage matches the new defineComponent approach.

apps/web-naive/src/adapter/component/index.ts (3)

6-6: Import of Component is correct.
Consistent with the refactored defineComponent usage.


9-9: Import of Recordable aligns with usage.
Using a record type helps store arbitrary method mappings.


11-11: Vue composition API imports are valid.
The updated approach correctly leverages defineComponent, getCurrentInstance, and ref.

packages/@core/ui-kit/form-ui/src/form-api.ts (6)

8-8: Good addition of Vue's ComponentPublicInstance import

This import is necessary for the new functionality that allows accessing component instances by field name.


61-64: Well-structured component reference map implementation

The private property componentRefMap is appropriately initialized as an empty Map and will store component instances mapped by their field names. The comment clearly explains its purpose in Chinese.


95-106: Good implementation of component reference retrieval method

The getFieldComponentRef method is well-typed with generic parameter support, allowing for flexible component instance retrieval. The implementation correctly handles the case when a field component isn't found in the map.


108-133: Thorough implementation of the focused field detection

The getFocusedField method effectively handles different component types:

  1. Direct HTMLElement instances
  2. Vue component instances with $el property
  3. Checks both direct focus and child element focus

This implementation aligns well with the PR objective of facilitating custom validation functions that need to know when a field loses focus.


193-193: Updated mount method signature to support component reference map

The mount method signature has been appropriately updated to accept the component reference map as a parameter.


200-200: Proper assignment of the component reference map during mounting

The form API correctly stores the provided component reference map, which enables the new component instance retrieval functionality.

pnpm-workspace.yaml (1)

21-22: Version updates for dependencies

These changes update various package dependencies to newer versions. While not directly related to the form API enhancement functionality, keeping dependencies updated is a good practice for security and compatibility reasons.

Also applies to: 24-27, 29-30, 34-35, 39-39, 48-48, 53-54, 62-64, 68-68, 81-82, 88-90, 96-98, 104-104, 123-123, 129-129, 136-136, 143-143, 147-147, 166-168, 178-178, 183-183

@mynetfan mynetfan merged commit 04dff33 into vbenjs:main Mar 9, 2025
14 checks passed
@mynetfan mynetfan deleted the feat/form-imporve branch March 9, 2025 18:56
@github-actions github-actions bot locked and limited conversation to collaborators Apr 9, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant