Эх сурвалжийг харах

fix: replace input component in `IconPicker` (#5047)

* fix: replace input component in `IconPicker`

* chore: fixed IconPicker demo
Netfan 9 сар өмнө
parent
commit
d1862fba27

+ 7 - 1
apps/web-antd/src/adapter/component/index.ts

@@ -102,7 +102,13 @@ async function initComponentAdapter() {
       return h(Button, { ...props, attrs, type: 'default' }, slots);
       return h(Button, { ...props, attrs, type: 'default' }, slots);
     },
     },
     Divider,
     Divider,
-    IconPicker,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs },
+        slots,
+      );
+    },
     Input: withDefaultPlaceholder(Input, 'input'),
     Input: withDefaultPlaceholder(Input, 'input'),
     InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
     InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
     InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
     InputPassword: withDefaultPlaceholder(InputPassword, 'input'),

+ 13 - 1
apps/web-ele/src/adapter/component/index.ts

@@ -88,7 +88,19 @@ async function initComponentAdapter() {
       return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
       return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
     },
     },
     Divider: ElDivider,
     Divider: ElDivider,
-    IconPicker,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        {
+          iconSlot: 'append',
+          modelValueProp: 'model-value',
+          inputComponent: ElInput,
+          ...props,
+          ...attrs,
+        },
+        slots,
+      );
+    },
     Input: withDefaultPlaceholder(ElInput, 'input'),
     Input: withDefaultPlaceholder(ElInput, 'input'),
     InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
     InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
     RadioGroup: ElRadioGroup,
     RadioGroup: ElRadioGroup,

+ 7 - 1
apps/web-naive/src/adapter/component/index.ts

@@ -89,7 +89,13 @@ async function initComponentAdapter() {
       return h(NButton, { ...props, attrs, type: 'primary' }, slots);
       return h(NButton, { ...props, attrs, type: 'primary' }, slots);
     },
     },
     Divider: NDivider,
     Divider: NDivider,
-    IconPicker,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'suffix', inputComponent: NInput, ...props, ...attrs },
+        slots,
+      );
+    },
     Input: withDefaultPlaceholder(NInput, 'input'),
     Input: withDefaultPlaceholder(NInput, 'input'),
     InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
     InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
     RadioGroup: NRadioGroup,
     RadioGroup: NRadioGroup,

+ 36 - 18
packages/effects/common-ui/src/components/icon-picker/icon-picker.vue

@@ -1,12 +1,11 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import { computed, ref, watch, watchEffect } from 'vue';
+import { computed, h, ref, type VNode, watch, watchEffect } from 'vue';
 
 
 import { usePagination } from '@vben/hooks';
 import { usePagination } from '@vben/hooks';
 import { EmptyIcon, Grip, listIcons } from '@vben/icons';
 import { EmptyIcon, Grip, listIcons } from '@vben/icons';
 import { $t } from '@vben/locales';
 import { $t } from '@vben/locales';
 import {
 import {
   Button,
   Button,
-  Input,
   Pagination,
   Pagination,
   PaginationEllipsis,
   PaginationEllipsis,
   PaginationFirst,
   PaginationFirst,
@@ -29,12 +28,24 @@ interface Props {
    * 图标列表
    * 图标列表
    */
    */
   icons?: string[];
   icons?: string[];
+  /** Input组件 */
+  inputComponent?: VNode;
+  /** 图标插槽名,预览图标将被渲染到此插槽中 */
+  iconSlot?: string;
+  /** input组件的值属性名称 */
+  modelValueProp?: string;
+  /** 图标样式 */
+  iconClass?: string;
 }
 }
 
 
 const props = withDefaults(defineProps<Props>(), {
 const props = withDefaults(defineProps<Props>(), {
   prefix: 'ant-design',
   prefix: 'ant-design',
   pageSize: 36,
   pageSize: 36,
   icons: () => [],
   icons: () => [],
+  inputComponent: () => h('div'),
+  iconSlot: 'default',
+  iconClass: 'size-4',
+  modelValueProp: 'value',
 });
 });
 
 
 const emit = defineEmits<{
 const emit = defineEmits<{
@@ -110,6 +121,19 @@ function close() {
   visible.value = false;
   visible.value = false;
 }
 }
 
 
+function onKeywordChange(v: string) {
+  keyword.value = v;
+}
+
+const searchInputProps = computed(() => {
+  return {
+    placeholder: $t('ui.iconPicker.search'),
+    [props.modelValueProp]: keyword.value,
+    [`onUpdate:${props.modelValueProp}`]: onKeywordChange,
+    class: 'mx-2',
+  };
+});
+
 defineExpose({ toggleOpenState, open, close });
 defineExpose({ toggleOpenState, open, close });
 </script>
 </script>
 <template>
 <template>
@@ -119,24 +143,18 @@ defineExpose({ toggleOpenState, open, close });
     content-class="p-0 pt-3"
     content-class="p-0 pt-3"
   >
   >
     <template #trigger>
     <template #trigger>
-      <slot :close="close" :icon="currentSelect" :open="open" name="trigger">
-        <div class="flex items-center gap-2">
-          <Input
-            :value="currentSelect"
-            class="flex-1 cursor-pointer"
-            v-bind="$attrs"
-            :placeholder="$t('ui.iconPicker.placeholder')"
-          />
-          <VbenIcon :icon="currentSelect || Grip" class="size-8" />
-        </div>
-      </slot>
+      <component
+        :is="inputComponent"
+        :[modelValueProp]="currentSelect"
+        :placeholder="$t('ui.iconPicker.placeholder')"
+      >
+        <template #[iconSlot]>
+          <VbenIcon :icon="currentSelect || Grip" class="size-4" />
+        </template>
+      </component>
     </template>
     </template>
     <div class="mb-2 flex w-full">
     <div class="mb-2 flex w-full">
-      <Input
-        v-model="keyword"
-        :placeholder="$t('ui.iconPicker.search')"
-        class="mx-2"
-      />
+      <component :is="inputComponent" v-bind="searchInputProps" />
     </div>
     </div>
 
 
     <template v-if="paginationList.length > 0">
     <template v-if="paginationList.length > 0">

+ 7 - 1
playground/src/adapter/component/index.ts

@@ -103,7 +103,13 @@ async function initComponentAdapter() {
       return h(Button, { ...props, attrs, type: 'default' }, slots);
       return h(Button, { ...props, attrs, type: 'default' }, slots);
     },
     },
     Divider,
     Divider,
-    IconPicker,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs },
+        slots,
+      );
+    },
     Input: withDefaultPlaceholder(Input, 'input'),
     Input: withDefaultPlaceholder(Input, 'input'),
     InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
     InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
     InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
     InputPassword: withDefaultPlaceholder(InputPassword, 'input'),

+ 6 - 27
playground/src/views/demos/features/icons/index.vue

@@ -1,9 +1,8 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { ref } from 'vue';
+import { h, ref } from 'vue';
 
 
 import { IconPicker, Page } from '@vben/common-ui';
 import { IconPicker, Page } from '@vben/common-ui';
 import {
 import {
-  IconifyIcon,
   MdiGithub,
   MdiGithub,
   MdiGoogle,
   MdiGoogle,
   MdiKeyboardEsc,
   MdiKeyboardEsc,
@@ -22,6 +21,8 @@ import {
 import { Card, Input } from 'ant-design-vue';
 import { Card, Input } from 'ant-design-vue';
 
 
 const iconValue = ref('ant-design:trademark-outlined');
 const iconValue = ref('ant-design:trademark-outlined');
+
+const inputComponent = h(Input);
 </script>
 </script>
 
 
 <template>
 <template>
@@ -84,23 +85,8 @@ const iconValue = ref('ant-design:trademark-outlined');
         <IconPicker class="w-[200px]" prefix="svg" />
         <IconPicker class="w-[200px]" prefix="svg" />
       </div>
       </div>
       <div class="mb-5 flex items-center gap-5">
       <div class="mb-5 flex items-center gap-5">
-        <span>完整替换触发组件:</span>
-        <IconPicker class="w-[200px]">
-          <template #trigger="{ icon }">
-            <Input
-              :value="icon"
-              placeholder="点击这里选择图标"
-              style="width: 300px"
-            >
-              <template #addonAfter>
-                <IconifyIcon
-                  :icon="icon || 'ant-design:appstore-filled'"
-                  class="text-2xl"
-                />
-              </template>
-            </Input>
-          </template>
-        </IconPicker>
+        <span>使用Input:</span>
+        <IconPicker :input-component="inputComponent" icon-slot="addonAfter" />
       </div>
       </div>
       <div class="flex items-center gap-5">
       <div class="flex items-center gap-5">
         <span>可手动输入,只能点击图标打开弹窗:</span>
         <span>可手动输入,只能点击图标打开弹窗:</span>
@@ -111,14 +97,7 @@ const iconValue = ref('ant-design:trademark-outlined');
           style="width: 300px"
           style="width: 300px"
         >
         >
           <template #addonAfter>
           <template #addonAfter>
-            <IconPicker v-model="iconValue" class="w-[200px]">
-              <template #trigger="{ icon }">
-                <IconifyIcon
-                  :icon="icon || 'ant-design:appstore-filled'"
-                  class="text-2xl"
-                />
-              </template>
-            </IconPicker>
+            <IconPicker v-model="iconValue" class="w-[200px]" />
           </template>
           </template>
         </Input>
         </Input>
       </div>
       </div>