Skip to content

feat: add preset alert, confirm, prompt components that can be simple called #5843

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

Merged
merged 2 commits into from
Apr 1, 2025

Conversation

mynetfan
Copy link
Collaborator

@mynetfan mynetfan commented Apr 1, 2025

Description

添加alert、confirm、prompt,可以无需在template中挂载即可快捷调用

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

    • Launched a new lightweight Alert component that supports alerts, confirmations, and prompts with flexible configurations, custom icons, and dynamic interactions.
    • Introduced interactive demo examples showcasing basic alerts, confirmation dialogs (including asynchronous behavior), and prompt modals for user input.
    • Enhanced UI components with additional icons and improved content formatting options.
    • Added a new prop to the RenderContent component for conditional line break rendering.
  • Documentation

    • Updated the sidebar navigation and added comprehensive documentation for the new Alert component.
    • Expanded localization support with prompt messages available in both English and Chinese.

@mynetfan mynetfan requested review from anncwb, vince292007, jinmao88 and a team as code owners April 1, 2025 06:55
Copy link

changeset-bot bot commented Apr 1, 2025

⚠️ No Changeset found

Latest commit: 8d63bd5

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

Copy link
Contributor

coderabbitai bot commented Apr 1, 2025

Walkthrough

This change introduces a new "Alert 轻量提示框" component across documentation, demos, and the UI kit. The modifications add a sidebar link and accompanying documentation for the Vben Alert component along with three demo components for alert, confirm, and prompt interactions. Additionally, updates include new icon exports, localized messages, alert builder functions, and several alert-dialog related Vue components for both popup-ui and shadcn-ui. Lastly, the playground now integrates these alert functionalities with new functions demonstrating alerts, confirmations, and prompts.

Changes

Affected Files Change Summary
docs/…/config/zh.mts, docs/…/vben-alert.md, docs/…/demos/vben-alert/*/index.vue Added a new sidebar entry for "Alert 轻量提示框", new documentation, and demo examples for alert, confirm, and prompt components.
packages/@core/base/icons/src/lucide.ts, packages/@core/composables/src/use-simple-locale/messages.ts Added new icon exports (CircleAlert, CircleX) and localized message entries for prompt in both English and Chinese.
packages/@core/ui-kit/popup-ui/src/alert/*, packages/@core/ui-kit/popup-ui/src/index.ts Introduced new alert builder functions (vbenAlert, vbenConfirm, vbenPrompt, clearAllAlerts), alert types, and components along with updated index exports.
packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue, packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/*, packages/@core/ui-kit/shadcn-ui/src/ui/index.ts Added a new renderBr prop and a suite of alert-dialog components (e.g. AlertDialog, AlertDialogAction, etc.) with consolidated re-exports.
playground/src/views/examples/modal/index.vue Integrated alert, confirm, and prompt functionalities with new functions (openAlert, openConfirm, openPrompt) and cleanup logic on component unmount.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant P as Playground Modal
  participant AB as AlertBuilder
  participant AD as AlertDialog

  U->>P: Clicks Alert/Confirm/Prompt Button
  P->>AB: Calls corresponding function (alert/confirm/prompt)
  AB->>AD: Render AlertDialog component
  AD-->>AB: User interacts (confirm/cancel/input)
  AB-->>P: Returns result (resolve/reject Promise)
  P-->>U: Displays outcome via alert messages
Loading

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • anncwb
  • vince292007

Poem

I'm a rabbit on the run,
Hopping through code under the sun.
Alerts and prompts, clear as day,
Bringing interaction our way.
With each new feature, I dance and play,
Celebrate the change in a bright, bouncy display!
🐇✨

✨ 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 plan to trigger planning for file edits and PR creation.
  • @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: 1

🧹 Nitpick comments (8)
packages/@core/ui-kit/popup-ui/src/alert/alert.ts (1)

5-28: Comprehensive and well-documented AlertProps interface!

The AlertProps type definition provides a thorough set of configuration options with clear JSDoc comments. The flexibility to use either Component or string for content, and the support for async operations in beforeClose are particularly valuable.

One suggestion: Consider making the content property optional in certain contexts (like simple alerts) by adding a question mark, or providing a default empty string value in the implementation if needed.

docs/src/demos/vben-alert/prompt/index.vue (1)

6-16: Consider using a more descriptive canceled message.

The error message when the prompt is canceled simply says "Canceled". Consider providing a more descriptive message that helps users understand what was canceled.

.catch(() => {
-  alert('Canceled');
+  alert('You canceled the prompt input.');
});
packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogContent.vue (1)

62-90: Consider improving the accessibility of the dialog.

While the component is well-structured, there's no explicit focus management for accessibility. When dialogs open, focus should move to the dialog and return to the previous element when closed.

<script setup lang="ts">
import type {
  AlertDialogContentEmits,
  AlertDialogContentProps,
} from 'radix-vue';

import type { ClassType } from '@vben-core/typings';

- import { computed, ref } from 'vue';
+ import { computed, ref, onMounted, onUpdated } from 'vue';

import { cn } from '@vben-core/shared/utils';

// ... existing imports ...

const contentRef = ref<InstanceType<typeof AlertDialogContent> | null>(null);
+ 
+ // Store the element that had focus before the dialog opened
+ const previousFocus = ref<HTMLElement | null>(null);
+ 
+ // Focus the dialog content when it opens
+ function focusDialog() {
+   if (props.open && contentRef.value?.$el) {
+     previousFocus.value = document.activeElement as HTMLElement;
+     contentRef.value.$el.focus();
+   } else if (!props.open && previousFocus.value) {
+     // Return focus when dialog closes
+     previousFocus.value.focus();
+     previousFocus.value = null;
+   }
+ }
+ 
+ onMounted(focusDialog);
+ onUpdated(focusDialog);

function onAnimationEnd(event: AnimationEvent) {
  // ... existing code ...
}
</script>

<template>
  <AlertDialogPortal>
    <!-- ... existing template ... -->
    <AlertDialogContent
      ref="contentRef"
      :style="{ ...(zIndex ? { zIndex } : {}), position: 'fixed' }"
+     tabindex="-1"
      @animationend="onAnimationEnd"
      v-bind="forwarded"
      :class="
        cn(
          'z-popup bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] w-full p-6 shadow-lg outline-none sm:rounded-xl',
          props.class,
        )
      "
    >
      <slot></slot>
    </AlertDialogContent>
  </AlertDialogPortal>
</template>
playground/src/views/examples/modal/index.vue (1)

151-169: Remove unnecessary async keyword.

The beforeClose handler is marked as async but doesn't use await anywhere, so the async keyword is unnecessary.

async function openPrompt() {
  prompt<string>({
-    async beforeClose(val) {
+    beforeClose(val) {
      if (val === '芝士') {
        message.error('不能吃芝士');
        return false;
      }
    },
    componentProps: { placeholder: '不能吃芝士...' },
    content: '中午吃了什么?',
    icon: 'question',
  })
packages/@core/ui-kit/popup-ui/src/alert/alert.vue (1)

86-88: Check the logic in icon rendering.

This code is inside an else block that only executes when props.icon is falsy, but then it tries to assign props.icon to iconRender. This assignment will always result in null since we're already in the else branch where props.icon is falsy.

  } else {
-    iconRender = props.icon ?? null;
+    iconRender = null;
  }
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (3)

46-50: Simplify conditional logic.

The nested condition has a redundant check. If arg1 is not a string, there's no need to explicitly check !isString(arg1) again in the else-if branch.

    if (arg1) {
      if (isString(arg1)) {
        options.title = arg1;
-      } else if (!isString(arg1)) {
+      } else {
        // 如果第二个参数是对象,则合并到选项中
        Object.assign(options, arg1);
      }
    }

78-78: Use translation for error message.

Consider using the translation system for the error message instead of hardcoded English text, to maintain consistency with the rest of the application's localization.

- reject(new Error('dialog cancelled'));
+ reject(new Error($t.value('dialogCancelled')));

111-132: Consider simplifying the vbenConfirm implementation.

The current implementation is relatively complex with multiple conditionals for different parameter combinations. Consider refactoring to simplify the logic by normalizing the parameters first, then making a single call to vbenAlert.

export function vbenConfirm(
  arg0: AlertProps | string,
  arg1?: Partial<AlertProps> | string,
  arg2?: Partial<AlertProps>,
): Promise<void> {
  const defaultProps: Partial<AlertProps> = {
    showCancel: true,
  };
-  if (!arg1) {
-    return isString(arg0)
-      ? vbenAlert(arg0, defaultProps)
-      : vbenAlert({ ...defaultProps, ...arg0 });
-  } else if (!arg2) {
-    return isString(arg1)
-      ? vbenAlert(arg0 as string, arg1, defaultProps)
-      : vbenAlert(arg0 as string, { ...defaultProps, ...arg1 });
-  }
-  return vbenAlert(arg0 as string, arg1 as string, {
-    ...defaultProps,
-    ...arg2,
-  });
+  // Create normalized parameters for vbenAlert
+  let normalizedArg0 = arg0;
+  let normalizedArg1 = arg1;
+  let normalizedArg2 = { ...defaultProps, ...(arg2 || {}) };
+  
+  // Handle different parameter combinations
+  if (!arg1) {
+    if (isString(arg0)) {
+      normalizedArg1 = defaultProps;
+    } else {
+      normalizedArg0 = { ...defaultProps, ...arg0 };
+      normalizedArg1 = undefined;
+      normalizedArg2 = undefined;
+    }
+  } else if (!arg2) {
+    if (isString(arg1)) {
+      normalizedArg2 = defaultProps;
+    } else {
+      normalizedArg1 = { ...defaultProps, ...arg1 };
+      normalizedArg2 = undefined;
+    }
+  }
+  
+  // Make a single call with normalized parameters
+  return vbenAlert(normalizedArg0, normalizedArg1, normalizedArg2);
}

Alternative simpler approach:

export function vbenConfirm(
  arg0: AlertProps | string,
  arg1?: Partial<AlertProps> | string,
  arg2?: Partial<AlertProps>,
): Promise<void> {
  // Process arguments the same way as vbenAlert, but add showCancel: true
  if (isString(arg0)) {
    // String message format
    const options = arg2 || (typeof arg1 === 'object' ? arg1 : {});
    const title = typeof arg1 === 'string' ? arg1 : undefined;
    return vbenAlert(arg0, title, { showCancel: true, ...options });
  } else {
    // Object format
    return vbenAlert({ showCancel: true, ...arg0 });
  }
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3abc2 and 624e38a.

📒 Files selected for processing (23)
  • docs/.vitepress/config/zh.mts (1 hunks)
  • docs/src/components/common-ui/vben-alert.md (1 hunks)
  • docs/src/demos/vben-alert/alert/index.vue (1 hunks)
  • docs/src/demos/vben-alert/confirm/index.vue (1 hunks)
  • docs/src/demos/vben-alert/prompt/index.vue (1 hunks)
  • packages/@core/base/icons/src/lucide.ts (1 hunks)
  • packages/@core/composables/src/use-simple-locale/messages.ts (2 hunks)
  • packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (1 hunks)
  • packages/@core/ui-kit/popup-ui/src/alert/alert.ts (1 hunks)
  • packages/@core/ui-kit/popup-ui/src/alert/alert.vue (1 hunks)
  • packages/@core/ui-kit/popup-ui/src/alert/index.ts (1 hunks)
  • packages/@core/ui-kit/popup-ui/src/index.ts (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue (3 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialog.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogAction.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogCancel.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogContent.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogDescription.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogOverlay.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogTitle.vue (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/index.ts (1 hunks)
  • packages/@core/ui-kit/shadcn-ui/src/ui/index.ts (1 hunks)
  • playground/src/views/examples/modal/index.vue (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (2)
packages/@core/ui-kit/popup-ui/src/alert/index.ts (4)
  • vbenAlert (5-5)
  • vbenConfirm (7-7)
  • vbenPrompt (8-8)
  • clearAllAlerts (6-6)
packages/@core/ui-kit/popup-ui/src/alert/alert.ts (1)
  • AlertProps (5-28)
🪛 GitHub Actions: Build detection
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts

[error] 19-19: error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

🔇 Additional comments (35)
packages/@core/ui-kit/popup-ui/src/index.ts (1)

1-1: LGTM: Clean export addition for new alert functionality

The export statement is correctly placed at the beginning of the file, maintaining alphabetical order with the other exports, and follows the same pattern as the existing exports.

packages/@core/base/icons/src/lucide.ts (1)

18-18: LGTM: Appropriate icon additions for alert components

The CircleAlert and CircleX icons are well-suited for the new alert, confirm, and prompt functionalities being added, and they're properly exported from the lucide-vue-next package. The export list maintains alphabetical ordering.

Also applies to: 21-21

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogOverlay.vue (1)

1-8: LGTM: Well-structured overlay component with scroll locking

This component implements a background overlay with proper z-index and positioning through CSS classes, and correctly uses the useScrollLock composable to prevent background scrolling when the alert dialog is active.

packages/@core/ui-kit/shadcn-ui/src/ui/index.ts (1)

2-2: LGTM: Clean alert-dialog module export

The export statement is correctly placed in alphabetical order with the other exports, making the alert-dialog components accessible through the UI module's public API.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogCancel.vue (1)

1-13: Clean wrapper implementation for the AlertDialogCancel component.

The component follows best practices by creating a thin wrapper around the radix-vue component, properly defining TypeScript props, and allowing for slot content to be passed through.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogAction.vue (1)

1-13: Well-structured component implementation.

The component properly wraps the radix-vue AlertDialogAction component, following the same pattern as other alert dialog components. The implementation is clean and follows Vue best practices with script setup and proper TypeScript typing.

docs/.vitepress/config/zh.mts (1)

171-174: Appropriate sidebar addition for the new Alert component.

The change correctly adds the new Alert component to the sidebar navigation under the "通用组件" (Common Components) section, following the established pattern for documentation organization.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/index.ts (1)

1-6: Well-organized exports for the alert dialog components.

The index file properly exports all six alert dialog components, making them available for import throughout the application. The export pattern is consistent with modern JavaScript best practices.

packages/@core/composables/src/use-simple-locale/messages.ts (1)

9-9: Appropriate localization entries added for the new prompt feature.

The additions of "prompt" entries in both English and Chinese locales are consistent with the existing localization patterns and follow alphabetical ordering.

Also applies to: 18-18

packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue (3)

6-6: LGTM: Import updated to include isString utility.

The import statement has been correctly expanded to include the isString utility needed for the new functionality.


17-20: Good addition of renderBr prop with appropriate defaults.

The new renderBr prop is well-defined with the correct type and a sensible default value of false, ensuring backward compatibility.


31-44: Enhanced content rendering with proper line break support.

The implementation correctly handles multiline strings by splitting on newlines and inserting proper <br> elements. This will improve text formatting in dialogs and alerts.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogTitle.vue (2)

1-19: Well-structured component with proper TypeScript integration.

The component correctly leverages TypeScript typing from radix-vue and implements prop forwarding using Vue 3's Composition API. The computed property pattern for delegated props is a clean approach.


21-30: Clean template with appropriate styling.

The template properly binds forwarded props and applies sensible default styling for a dialog title. The use of the cn utility for class merging is a good practice for maintaining consistent styling while allowing customization.

docs/src/demos/vben-alert/alert/index.vue (3)

1-7: Clean setup and imports for the alert demo.

The imports are minimal and focused on what's needed for the demonstration.


8-24: Comprehensive demonstration of alert functionality.

The three functions effectively showcase different alert capabilities:

  1. Basic text alert
  2. Alert with icon
  3. Alert with custom component content

The implementation is clean and follows Vue 3 best practices, particularly in the use of the h function for rendering custom content.


25-31: Simple and intuitive UI for testing alert variations.

The template provides a clear and straightforward way for users to test the different alert types. The button layout with appropriate spacing makes the demo easy to use.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialog.vue (1)

1-16: Well-structured component implementation!

The component is implemented following Vue 3 best practices with script setup and TypeScript. It effectively wraps the Radix Vue AlertDialogRoot component and uses the useForwardPropsEmits utility to elegantly forward all props and events to the underlying component, providing a clean abstraction layer.

docs/src/demos/vben-alert/confirm/index.vue (4)

4-12: Excellent implementation of basic confirmation dialog!

The showConfirm function demonstrates a clean promise-based approach to handling confirmation and cancellation, with appropriate feedback shown to the user in both cases.


14-19: Good demonstration of icon-enhanced confirmation!

The showIconConfirm function shows how to include visual indicators through icons, which is useful for providing context at a glance.


21-31: Excellent example of asynchronous confirmation!

This demonstrates an advanced use case with beforeClose returning a Promise that delays resolution, showcasing how to handle async operations (like API calls) before closing the dialog.


33-39: Clean and intuitive template!

The template layout with appropriately labeled buttons makes the demo clear and easy to understand. The flex layout with gap spacing provides a clean UI.

packages/@core/ui-kit/popup-ui/src/alert/alert.ts (1)

3-3: Well-defined IconType enum!

The IconType is appropriately defined as a union of string literals, making it type-safe and ensuring only valid icon types can be used.

packages/@core/ui-kit/popup-ui/src/alert/index.ts (1)

1-9: Clean and developer-friendly export pattern!

The export organization follows best practices with:

  1. A clear barrel pattern for exporting all type definitions
  2. Explicit export of the Alert component
  3. Thoughtful renaming of exports (e.g., vbenAlert as alert) to provide a cleaner API while maintaining prefixed internal names

This approach enhances developer experience while maintaining good internal code organization.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogDescription.vue (1)

1-28: The component looks well-structured and follows best practices.

This component is well-implemented, correctly forwarding props to the underlying Radix component while properly handling class merging. The use of computed properties and TypeScript typing demonstrates good practices for component composition.

docs/src/demos/vben-alert/prompt/index.vue (1)

18-34: This component example looks good.

The select prompt implementation correctly demonstrates how to use a custom component inside a prompt. The implementation shows good practices with promise handling and user feedback.

packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogContent.vue (1)

47-56: Animation event handling looks good.

The animation event handling is well-implemented, correctly checking that the event target matches the content element before emitting events. This prevents unintended event emissions.

playground/src/views/examples/modal/index.vue (4)

116-123: The alert implementation looks good.

The alert implementation correctly demonstrates basic usage with icon support and proper promise handling when the user closes the dialog.


125-128: Good cleanup in onBeforeUnmount.

Cleaning up alerts when the component unmounts is a good practice to prevent memory leaks and orphaned UI elements.


130-149: The confirm implementation looks good.

The confirm dialog correctly demonstrates async behavior in the beforeClose callback with proper promise handling for both confirmation and cancellation scenarios.


262-269: Card UI for quick alerts looks good.

The card with buttons for Alert, Confirm, and Prompt provides a clean and intuitive interface for demonstrating these features.

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

1-101: Documentation is comprehensive and well-structured.

The documentation clearly explains the purpose of the Vben Alert component, its usage scenarios, and provides examples for all three types (alert, confirm, and prompt). The type definitions and function signatures are well-documented with helpful comments.

packages/@core/ui-kit/popup-ui/src/alert/alert.vue (2)

98-113: Well-implemented async beforeClose handling.

The component properly handles the asynchronous beforeClose hook with loading states, ensuring the dialog only closes when the hook resolves to a non-false value. The try-finally block guarantees that loading state is reset even if the hook throws an exception.


115-180: Well-structured dialog with proper accessibility features.

The template structure properly uses AlertDialog components with appropriate roles and event handling. The UI provides visual feedback during loading state and clearly distinguishes between confirm and cancel actions.

packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (1)

134-194: Well-implemented prompt function with focus management.

The vbenPrompt function is well-designed with proper handling of:

  • Component props and model binding
  • Focus management for accessibility
  • Passing user input to beforeClose callback
  • Supporting custom input components

The implementation follows best practices for creating dynamic forms with Vue.

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 (7)
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (7)

58-58: Avoid using any type for component instance.

Using any type bypasses TypeScript's type checking. Consider using a more specific type or unknown as a safer alternative.

- const alertRef = { container, instance: null as any };
+ const alertRef = { container, instance: null as unknown as Component };

73-77: Consider a more graceful approach for handling dialog cancellation.

Rejecting the promise with an error for a cancellation might lead to unhandled promise rejections if consumers don't use try/catch. Consider resolving with a result object that includes success status.

if (isConfirm) {
-  resolve();
+  resolve({ confirmed: true });
} else {
-  reject(new Error('dialog cancelled'));
+  resolve({ confirmed: false, cancelled: true });
}

117-129: Simplify the conditional logic for better readability.

The nested conditionals make the code harder to follow. Consider restructuring to make the flow clearer.

const defaultProps: Partial<AlertProps> = {
  showCancel: true,
};

- if (!arg1) {
-   return isString(arg0)
-     ? vbenAlert(arg0, defaultProps)
-     : vbenAlert({ ...defaultProps, ...arg0 });
- } else if (!arg2) {
-   return isString(arg1)
-     ? vbenAlert(arg0 as string, arg1, defaultProps)
-     : vbenAlert(arg0 as string, { ...defaultProps, ...arg1 });
- }
- return vbenAlert(arg0 as string, arg1 as string, {
-   ...defaultProps,
-   ...arg2,
- });
+ // Case 1: Only first argument provided
+ if (!arg1) {
+   if (isString(arg0)) {
+     return vbenAlert(arg0, defaultProps);
+   }
+   return vbenAlert({ ...defaultProps, ...arg0 });
+ }
+
+ // Case 2: First and second arguments provided
+ if (!arg2) {
+   if (isString(arg1)) {
+     return vbenAlert(arg0 as string, arg1, defaultProps);
+   }
+   return vbenAlert(arg0 as string, { ...defaultProps, ...arg1 });
+ }
+
+ // Case 3: All three arguments provided
+ return vbenAlert(arg0 as string, arg1 as string, {
+   ...defaultProps,
+   ...arg2,
+ });

132-142: Consider extracting the complex type definition to improve readability.

The function signature is complex and could be simplified by extracting the option type.

+export type PromptOptions<T = any> = Omit<AlertProps, 'beforeClose'> & {
+  beforeClose?: (val: T) => boolean | Promise<boolean | undefined> | undefined;
+  component?: Component;
+  componentProps?: Recordable<any>;
+  defaultValue?: T;
+  modelPropName?: string;
+};

-export async function vbenPrompt<T = any>(
-  options: Omit<AlertProps, 'beforeClose'> & {
-    beforeClose?: (
-      val: T,
-    ) => boolean | Promise<boolean | undefined> | undefined;
-    component?: Component;
-    componentProps?: Recordable<any>;
-    defaultValue?: T;
-    modelPropName?: string;
-  },
-): Promise<T | undefined> {
+export async function vbenPrompt<T = any>(
+  options: PromptOptions<T>
+): Promise<T | undefined> {

179-187: Improve error handling for component focus.

The focus handling logic has multiple conditionals but no error catching. This could fail silently if there are issues with the components.

onOpened() {
  // 组件挂载完成后,自动聚焦到输入组件
+  try {
    if (
      componentRef.component?.exposed &&
      isFunction(componentRef.component.exposed.focus)
    ) {
      componentRef.component.exposed.focus();
    } else if (componentRef.el && isFunction(componentRef.el.focus)) {
      componentRef.el.focus();
    }
+  } catch (e) {
+    console.warn('Failed to focus prompt input:', e);
+  }
},

190-191: Handle potential errors when awaiting vbenConfirm.

The await for vbenConfirm is not wrapped in a try/catch block. If the confirm is rejected (e.g., if the user cancels), this could throw an uncaught exception.

-  await vbenConfirm(props);
-  return modelValue.value;
+  try {
+    await vbenConfirm(props);
+    return modelValue.value;
+  } catch (e) {
+    // User cancelled the dialog
+    return undefined;
+  }

194-203: Consider returning the number of cleared alerts.

The function doesn't provide any feedback on how many alerts were cleared. This could be useful for debugging or logging purposes.

-export function clearAllAlerts() {
+export function clearAllAlerts(): number {
+  const count = alerts.value.length;
  alerts.value.forEach((alert) => {
    // 从DOM中移除容器
    render(null, alert.container);
    if (alert.container.parentNode) {
      alert.container.remove();
    }
  });
  alerts.value = [];
+  return count;
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 624e38a and 8d63bd5.

📒 Files selected for processing (1)
  • packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (2)
packages/@core/ui-kit/popup-ui/src/alert/index.ts (4)
  • vbenAlert (5-5)
  • vbenConfirm (7-7)
  • vbenPrompt (8-8)
  • clearAllAlerts (6-6)
packages/@core/ui-kit/popup-ui/src/alert/alert.ts (1)
  • AlertProps (5-28)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: post-update (windows-latest)
🔇 Additional comments (2)
packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts (2)

15-15: Consider adding an exported readonly alertList for external consumption.

The alerts ref is well-typed, but you might want to provide a readonly version for external consumers to check active alerts.

const alerts = ref<Array<{ container: HTMLElement; instance: Component }>>([]);
+export const alertList = readonly(alerts) as Readonly<Ref<Array<{ container: HTMLElement; instance: Component }>>>;

1-204: Overall: Well-implemented alert system with good architecture.

The alert system is well-designed with a promise-based API, proper DOM management, and internationalization support. The implementation follows good practices for dynamically creating and managing Vue components.

A few architectural suggestions:

  1. Consider adding a way to globally configure default options
  2. Add support for custom CSS/theme classes
  3. Document escape key and outside click behavior

These functions will make it much easier for developers to use alerts, confirms, and prompts without complex template markup.

@mynetfan mynetfan merged commit 44138f5 into vbenjs:main Apr 1, 2025
14 checks passed
@mynetfan mynetfan deleted the feat/alert branch April 1, 2025 07:10
caszhou pushed a commit to YueChengMinJie/vue-vben-admin that referenced this pull request Apr 2, 2025
… called (vbenjs#5843)

* feat: add preset alert, confirm, prompt components that can be simple called

* fix: type define
@github-actions github-actions bot locked and limited conversation to collaborators May 2, 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