Browse Source

fix: select components used in modal pop-ups cannot be selected (#4368)

* fix: select components used in modal pop-ups cannot be selected

* chore: update ci

* chore: update css
Vben 6 months ago
parent
commit
855ac02622

+ 7 - 1
.github/workflows/build.yml

@@ -20,7 +20,13 @@ permissions:
 jobs:
   post-update:
     # if: ${{ github.actor == 'dependabot[bot]' }}
-    runs-on: ubuntu-latest
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os:
+          - ubuntu-latest
+          # - macos-latest
+          - windows-latest
     steps:
       - name: Checkout code
         uses: actions/checkout@v4

+ 5 - 0
packages/@core/base/design/src/css/global.css

@@ -32,9 +32,13 @@
   body,
   html {
     @apply size-full overscroll-none;
+
+    /* scrollbar-gutter: stable; */
   }
 
   body {
+    @apply !pointer-events-auto;
+
     min-height: 100vh;
 
     /* overflow: overlay; */
@@ -90,6 +94,7 @@
   }
 
   /* 只有非mac下才进行调整,mac下使用默认滚动条 */
+
   html:not([data-platform='macOs']) {
     ::-webkit-scrollbar {
       @apply h-[10px] w-[10px];

+ 1 - 0
packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts

@@ -41,6 +41,7 @@ export class ModalApi {
       isOpen: false,
       loading: false,
       modal: true,
+      openAutoFocus: false,
       showCancelButton: true,
       showConfirmButton: true,
       title: '',

+ 4 - 0
packages/@core/ui-kit/popup-ui/src/modal/modal.ts

@@ -75,6 +75,10 @@ export interface ModalProps {
    * @default true
    */
   modal?: boolean;
+  /**
+   * 是否自动聚焦
+   */
+  openAutoFocus?: boolean;
   /**
    * 是否显示取消按钮
    * @default true

+ 9 - 0
packages/@core/ui-kit/popup-ui/src/modal/modal.vue

@@ -68,6 +68,7 @@ const {
   header,
   loading: showLoading,
   modal,
+  openAutoFocus,
   showCancelButton,
   showConfirmButton,
   title,
@@ -133,6 +134,13 @@ function escapeKeyDown(e: KeyboardEvent) {
     e.preventDefault();
   }
 }
+
+function handerOpenAutoFocus(e: Event) {
+  if (!openAutoFocus.value) {
+    e?.preventDefault();
+  }
+}
+
 // pointer-down-outside
 function pointerDownOutside(e: Event) {
   const target = e.target as HTMLElement;
@@ -166,6 +174,7 @@ function pointerDownOutside(e: Event) {
       close-class="top-3"
       @escape-key-down="escapeKeyDown"
       @interact-outside="interactOutside"
+      @open-auto-focus="handerOpenAutoFocus"
       @pointer-down-outside="pointerDownOutside"
     >
       <DialogHeader

+ 24 - 3
packages/effects/common-ui/src/ui/authentication/code-login.vue

@@ -22,6 +22,18 @@ interface Props {
    * @zh_CN 登陆路径
    */
   loginPath?: string;
+  /**
+   * @zh_CN 标题
+   */
+  title?: string;
+  /**
+   * @zh_CN 描述
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 按钮文本
+   */
+  submitButtonText?: string;
 }
 
 defineOptions({
@@ -31,6 +43,9 @@ defineOptions({
 const props = withDefaults(defineProps<Props>(), {
   loading: false,
   loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
 });
 
 const emit = defineEmits<{
@@ -69,16 +84,22 @@ function goToLogin() {
 <template>
   <div>
     <Title>
-      {{ $t('authentication.welcomeBack') }} 📲
+      <slot name="title">
+        {{ title || $t('authentication.welcomeBack') }} 📲
+      </slot>
       <template #desc>
         <span class="text-muted-foreground">
-          {{ $t('authentication.codeSubtitle') }}
+          <slot name="subTitle">
+            {{ subTitle || $t('authentication.codeSubtitle') }}
+          </slot>
         </span>
       </template>
     </Title>
     <Form />
     <VbenButton :loading="loading" class="w-full" @click="handleSubmit">
-      {{ $t('common.login') }}
+      <slot name="submitButtonText">
+        {{ submitButtonText || $t('common.login') }}
+      </slot>
     </VbenButton>
     <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
       {{ $t('common.back') }}

+ 25 - 5
packages/effects/common-ui/src/ui/authentication/forget-password.vue

@@ -11,6 +11,7 @@ import { VbenButton } from '@vben-core/shadcn-ui';
 import Title from './auth-title.vue';
 
 interface Props {
+  formSchema: VbenFormSchema[];
   /**
    * @zh_CN 是否处于加载处理状态
    */
@@ -19,8 +20,18 @@ interface Props {
    * @zh_CN 登陆路径
    */
   loginPath?: string;
-
-  formSchema: VbenFormSchema[];
+  /**
+   * @zh_CN 标题
+   */
+  title?: string;
+  /**
+   * @zh_CN 描述
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 按钮文本
+   */
+  submitButtonText?: string;
 }
 
 defineOptions({
@@ -30,6 +41,9 @@ defineOptions({
 const props = withDefaults(defineProps<Props>(), {
   loading: false,
   loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
 });
 
 const emit = defineEmits<{
@@ -65,16 +79,22 @@ function goToLogin() {
 <template>
   <div>
     <Title>
-      {{ $t('authentication.forgetPassword') }} 🤦🏻‍♂️
+      <slot name="title">
+        {{ title || $t('authentication.forgetPassword') }} 🤦🏻‍♂️
+      </slot>
       <template #desc>
-        {{ $t('authentication.forgetPasswordSubtitle') }}
+        <slot name="subTitle">
+          {{ subTitle || $t('authentication.forgetPasswordSubtitle') }}
+        </slot>
       </template>
     </Title>
     <Form />
 
     <div>
       <VbenButton class="mt-2 w-full" @click="handleSubmit">
-        {{ $t('authentication.sendResetLink') }}
+        <slot name="submitButtonText">
+          {{ submitButtonText || $t('authentication.sendResetLink') }}
+        </slot>
       </VbenButton>
       <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
         {{ $t('common.back') }}

+ 14 - 5
packages/effects/common-ui/src/ui/authentication/login.vue

@@ -34,6 +34,7 @@ const props = withDefaults(defineProps<Props>(), {
   showRegister: true,
   showRememberMe: true,
   showThirdPartyLogin: true,
+  submitButtonText: '',
   subTitle: '',
   title: '',
 });
@@ -86,10 +87,14 @@ onMounted(() => {
   <div @keydown.enter.prevent="handleSubmit">
     <slot name="title">
       <Title>
-        {{ title || `${$t('authentication.welcomeBack')} 👋🏻` }}
+        <slot name="title">
+          {{ title || `${$t('authentication.welcomeBack')} 👋🏻` }}
+        </slot>
         <template #desc>
           <span class="text-muted-foreground">
-            {{ subTitle || $t('authentication.loginSubtitle') }}
+            <slot name="subTitle">
+              {{ subTitle || $t('authentication.loginSubtitle') }}
+            </slot>
           </span>
         </template>
       </Title>
@@ -101,8 +106,12 @@ onMounted(() => {
       v-if="showRememberMe || showForgetPassword"
       class="mb-6 flex justify-between"
     >
-      <div v-if="showRememberMe" class="flex-center">
-        <VbenCheckbox v-model:checked="rememberMe" name="rememberMe">
+      <div class="flex-center">
+        <VbenCheckbox
+          v-if="showRememberMe"
+          v-model:checked="rememberMe"
+          name="rememberMe"
+        >
           {{ $t('authentication.rememberMe') }}
         </VbenCheckbox>
       </div>
@@ -116,7 +125,7 @@ onMounted(() => {
       </span>
     </div>
     <VbenButton :loading="loading" class="w-full" @click="handleSubmit">
-      {{ $t('common.login') }}
+      {{ submitButtonText || $t('common.login') }}
     </VbenButton>
 
     <div

+ 29 - 3
packages/effects/common-ui/src/ui/authentication/qrcode-login.vue

@@ -18,6 +18,22 @@ interface Props {
    * @zh_CN 登陆路径
    */
   loginPath?: string;
+  /**
+   * @zh_CN 标题
+   */
+  title?: string;
+  /**
+   * @zh_CN 描述
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 按钮文本
+   */
+  submitButtonText?: string;
+  /**
+   * @zh_CN 描述
+   */
+  description?: string;
 }
 
 defineOptions({
@@ -25,8 +41,12 @@ defineOptions({
 });
 
 const props = withDefaults(defineProps<Props>(), {
+  description: '',
   loading: false,
   loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
 });
 
 const router = useRouter();
@@ -46,10 +66,14 @@ function goToLogin() {
 <template>
   <div>
     <Title>
-      {{ $t('authentication.welcomeBack') }} 📱
+      <slot name="title">
+        {{ title || $t('authentication.welcomeBack') }} 📱
+      </slot>
       <template #desc>
         <span class="text-muted-foreground">
-          {{ $t('authentication.qrcodeSubtitle') }}
+          <slot name="subTitle">
+            {{ subTitle || $t('authentication.qrcodeSubtitle') }}
+          </slot>
         </span>
       </template>
     </Title>
@@ -57,7 +81,9 @@ function goToLogin() {
     <div class="flex-col-center mt-6">
       <img :src="qrcode" alt="qrcode" class="w-1/2" />
       <p class="text-muted-foreground mt-4 text-sm">
-        {{ $t('authentication.qrcodePrompt') }}
+        <slot name="description">
+          {{ description || $t('authentication.qrcodePrompt') }}
+        </slot>
       </p>
     </div>
 

+ 26 - 3
packages/effects/common-ui/src/ui/authentication/register.vue

@@ -22,6 +22,18 @@ interface Props {
    * @zh_CN 登陆路径
    */
   loginPath?: string;
+  /**
+   * @zh_CN 标题
+   */
+  title?: string;
+  /**
+   * @zh_CN 描述
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 按钮文本
+   */
+  submitButtonText?: string;
 }
 
 defineOptions({
@@ -32,6 +44,9 @@ const props = withDefaults(defineProps<Props>(), {
   formSchema: () => [],
   loading: false,
   loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
 });
 
 const emit = defineEmits<{
@@ -66,13 +81,21 @@ function goToLogin() {
 <template>
   <div>
     <Title>
-      {{ $t('authentication.createAnAccount') }} 🚀
-      <template #desc> {{ $t('authentication.signUpSubtitle') }} </template>
+      <slot name="title">
+        {{ title || $t('authentication.createAnAccount') }} 🚀
+      </slot>
+      <template #desc>
+        <slot name="subTitle">
+          {{ subTitle || $t('authentication.signUpSubtitle') }}
+        </slot>
+      </template>
     </Title>
     <Form />
 
     <VbenButton :loading="loading" class="mt-2 w-full" @click="handleSubmit">
-      {{ $t('authentication.signUp') }}
+      <slot name="submitButtonText">
+        {{ submitButtonText || $t('authentication.signUp') }}
+      </slot>
     </VbenButton>
     <div class="mt-4 text-center text-sm">
       {{ $t('authentication.alreadyHaveAccount') }}

+ 4 - 0
packages/effects/common-ui/src/ui/authentication/types.ts

@@ -61,6 +61,10 @@ interface AuthenticationProps {
    * @zh_CN 登录框标题
    */
   title?: string;
+  /**
+   * @zh_CN 提交按钮文本
+   */
+  submitButtonText?: string;
 }
 
 interface LoginAndRegisterParams {

+ 2 - 2
packages/effects/layouts/src/authentication/toolbar.vue

@@ -31,9 +31,9 @@ const showTheme = computed(() => props.toolbarList.includes('theme'));
 <template>
   <div
     :class="{
-      'bg-accent z-10 rounded-3xl px-3 py-1': toolbarList.length > 1,
+      'bg-accent rounded-3xl px-3 py-1': toolbarList.length > 1,
     }"
-    class="flex-center absolute right-2 top-4"
+    class="flex-center absolute right-2 top-4 z-10"
   >
     <!-- Only show on medium and larger screens -->
     <div class="hidden md:flex">

+ 13 - 0
playground/src/views/examples/modal/form-model-demo.vue

@@ -27,6 +27,19 @@ const [Form, formApi] = useVbenForm({
       label: '字段2',
       rules: 'required',
     },
+    {
+      component: 'Select',
+      componentProps: {
+        options: [
+          { label: '选项1', value: '1' },
+          { label: '选项2', value: '2' },
+        ],
+        placeholder: '请输入',
+      },
+      fieldName: 'field3',
+      label: '字段3',
+      rules: 'required',
+    },
   ],
   showDefaultActions: false,
 });