diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 32718a94d1..00c687e3b4 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -blank_issues_enabled: false +blank_issues_enabled: true contact_links: - name: Create new issue url: https://vuecomponent.github.io/issue-helper/ diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index e955042384..84d4ffa90c 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -10,6 +10,27 @@ --- +## 4.2.6 + +- 🐞 Fix Modal component aria-hidden error problem under chrome [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823) +- 🐞 Fix the problem that the built-in input method of Safari automatically fills in the decimal point when inputting Chinese [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918) +- 🐞 Fix InputNumber component disabled style problem [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776) +- 🐞 Fix Select cannot lose focus problem [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819) + +## 4.2.5 + +- 🐞 Fix Empty component memory leak problem +- 🐞 Fix Image width & height property not working problem + +## 4.2.4 + +- 🐞 Fix Wave memory leak problem + +## 4.2.3 + +- 🌟 TourStep custom Button, support function children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628) +- 🐞 Fix the problem that the input value is hidden in Select and Cascader search multi-select mode [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640) + ## 4.2.2 - 🐞 Fix TreeSelect placeholder slot invalid [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545) diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index f4f51e14b9..c9b50d9631 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -10,6 +10,27 @@ --- +## 4.2.6 + +- 🐞 修复 Modal 组件在 chrome 下,aria-hidden 报错问题 [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823) +- 🐞 修复 Safari 下自带输入法 input 组件输入中文时,自动填写小数点问题 [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918) +- 🐞 修复 InputNumber 组件 disabled 样式问题 [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776) +- 🐞 修复 Select 无法失焦问题 [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819) + +## 4.2.5 + +- 🐞 修复 Empty 组件内存泄漏问题 +- 🐞 修复 Image width & height 属性不生效问题 + +## 4.2.4 + +- 🐞 修复 Wave 内存泄漏问题 + +## 4.2.3 + +- 🌟 TourStep 自定义 Button,支持函数 children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628) +- 🐞 修复 Select 和 Cascader 搜索多选模式下,输入值被隐藏问题 [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640) + ## 4.2.2 - 🐞 修复 TreeSelect placeholder 插槽无效 [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545) diff --git a/README-zh_CN.md b/README-zh_CN.md index c672231073..05a8f70302 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -73,6 +73,7 @@ $ yarn add ant-design-vue | [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | 在 DOM 模板中,您可以使用 ant-design-vue 组件的自定义事件(camelCase) | | [@formily/antdv](https://github.com/formilyjs/antdv) | 这是一个结合了 Formily 和 ant-design-vue 的组件库 | | [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | ant-design-vue 的 nuxt 模块扩展 | +| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | 基于 Ant Design X 设计规范的 Vue AI 界面解决方案 | ## 问答 diff --git a/README.md b/README.md index 853c16791b..3bc3fb0fc3 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ If you are in a bad network environment, you can try other registries and tools | [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | The library function, implemented in the DOM template, can use the custom event of the ant-design-vue component (camelCase) | | [@formily/antdv](https://github.com/formilyjs/antdv) | The Library with Formily and ant-design-vue | | [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | A nuxt module for ant-design-vue | +| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | A Vue AI interface solutions base on the Ant Design X design specification | ## Donation diff --git a/components/_util/transition.tsx b/components/_util/transition.tsx index fd6ebc4904..f4b69f31ed 100644 --- a/components/_util/transition.tsx +++ b/components/_util/transition.tsx @@ -5,7 +5,7 @@ import type { TransitionGroupProps, TransitionProps, } from 'vue'; -import { nextTick, Transition, TransitionGroup } from 'vue'; +import { nextTick } from 'vue'; import { tuple } from './type'; const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight'); @@ -126,6 +126,4 @@ const getTransitionName = (rootPrefixCls: string, motion: string, transitionName return `${rootPrefixCls}-${motion}`; }; -export { Transition, TransitionGroup, collapseMotion, getTransitionName, getTransitionDirection }; - -export default Transition; +export { collapseMotion, getTransitionName, getTransitionDirection }; diff --git a/components/_util/wave/WaveEffect.tsx b/components/_util/wave/WaveEffect.tsx index 1f3ce23d17..b59c8ff66a 100644 --- a/components/_util/wave/WaveEffect.tsx +++ b/components/_util/wave/WaveEffect.tsx @@ -159,6 +159,12 @@ function showWaveEffect(node: HTMLElement, className: string) { node?.insertBefore(holder, node?.firstChild); render(, holder); + return () => { + render(null, holder); + if (holder.parentElement) { + holder.parentElement.removeChild(holder); + } + }; } export default showWaveEffect; diff --git a/components/_util/wave/index.tsx b/components/_util/wave/index.tsx index 26ac1aff5e..26dab40f9c 100644 --- a/components/_util/wave/index.tsx +++ b/components/_util/wave/index.tsx @@ -33,13 +33,12 @@ export default defineComponent({ // =============================== Wave =============================== const showWave = useWave( - instance, computed(() => classNames(prefixCls.value, hashId.value)), wave, ); let onClick: (e: MouseEvent) => void; const clear = () => { - const node = findDOMNode(instance); + const node = findDOMNode(instance) as HTMLElement; node.removeEventListener('click', onClick, true); }; onMounted(() => { diff --git a/components/_util/wave/useWave.ts b/components/_util/wave/useWave.ts index 84e2a6effb..f88c361688 100644 --- a/components/_util/wave/useWave.ts +++ b/components/_util/wave/useWave.ts @@ -1,21 +1,25 @@ -import type { ComponentInternalInstance, ComputedRef, Ref } from 'vue'; +import type { ComputedRef, Ref } from 'vue'; +import { onBeforeUnmount, getCurrentInstance } from 'vue'; import { findDOMNode } from '../props-util'; import showWaveEffect from './WaveEffect'; export default function useWave( - instance: ComponentInternalInstance | null, className: Ref, wave?: ComputedRef<{ disabled?: boolean }>, ): VoidFunction { + const instance = getCurrentInstance(); + let stopWave: () => void; function showWave() { const node = findDOMNode(instance); - + stopWave?.(); if (wave?.value?.disabled || !node) { return; } - - showWaveEffect(node, className.value); + stopWave = showWaveEffect(node, className.value); } + onBeforeUnmount(() => { + stopWave?.(); + }); return showWave; } diff --git a/components/alert/index.tsx b/components/alert/index.tsx index 63a61aa6e0..f3dead2ba5 100644 --- a/components/alert/index.tsx +++ b/components/alert/index.tsx @@ -1,5 +1,5 @@ import type { CSSProperties, ExtractPropTypes, PropType } from 'vue'; -import { computed, defineComponent, shallowRef } from 'vue'; +import { computed, defineComponent, shallowRef, Transition } from 'vue'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined'; import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined'; @@ -11,7 +11,7 @@ import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled'; import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled'; import classNames from '../_util/classNames'; import PropTypes from '../_util/vue-types'; -import { getTransitionProps, Transition } from '../_util/transition'; +import { getTransitionProps } from '../_util/transition'; import { isValidElement } from '../_util/props-util'; import { tuple, withInstall } from '../_util/type'; import { cloneElement } from '../_util/vnode'; diff --git a/components/badge/Badge.tsx b/components/badge/Badge.tsx index 30195d049b..a0363732f4 100644 --- a/components/badge/Badge.tsx +++ b/components/badge/Badge.tsx @@ -3,9 +3,9 @@ import ScrollNumber from './ScrollNumber'; import classNames from '../_util/classNames'; import { getPropsSlot, flattenChildren } from '../_util/props-util'; import { cloneElement } from '../_util/vnode'; -import { getTransitionProps, Transition } from '../_util/transition'; +import { getTransitionProps } from '../_util/transition'; import type { ExtractPropTypes, CSSProperties, PropType } from 'vue'; -import { defineComponent, computed, ref, watch } from 'vue'; +import { defineComponent, computed, ref, watch, Transition } from 'vue'; import Ribbon from './Ribbon'; import useConfigInject from '../config-provider/hooks/useConfigInject'; import isNumeric from '../_util/isNumeric'; diff --git a/components/button/LoadingIcon.tsx b/components/button/LoadingIcon.tsx index 391527fd45..f865e09078 100644 --- a/components/button/LoadingIcon.tsx +++ b/components/button/LoadingIcon.tsx @@ -1,6 +1,5 @@ -import { defineComponent, nextTick } from 'vue'; +import { defineComponent, nextTick, Transition } from 'vue'; import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'; -import Transition from '../_util/transition'; const getCollapsedWidth = (node: HTMLSpanElement) => { if (node) { node.style.width = '0px'; diff --git a/components/calendar/index.zh-CN.md b/components/calendar/index.zh-CN.md index 3d0f68d1fd..725f2d5731 100644 --- a/components/calendar/index.zh-CN.md +++ b/components/calendar/index.zh-CN.md @@ -28,16 +28,16 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | -| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | 无 | | -| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | 无 | | -| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | 无 | | +| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | - | | +| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | - | | +| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | | | fullscreen | 是否全屏显示 | boolean | true | | | headerRender | 自定义头部内容 | v-slot:headerRender="{value: dayjs, type: string, onChange: f(), onTypeChange: f()}" | - | | | locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | | | mode | 初始模式,`month/year` | string | month | | -| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | 无 | | -| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | 无 | | -| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | 无 | | +| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | - | | +| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | - | | +| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | | value(v-model) | 展示日期 | [dayjs](https://day.js.org/) | 当前日期 | | | valueFormat | 可选,绑定值的格式,对 value、defaultValue 起作用。不指定则绑定值为 dayjs 对象 | string,[具体格式](https://day.js.org/docs/zh-CN/display/format) | - | | @@ -45,8 +45,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA | 事件名称 | 说明 | 回调参数 | | | --- | --- | --- | --- | --- | -| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | 无 | -| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | 无 | +| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | - | +| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | - | | select | 选择日期回调,包含来源信息 | function(date: Dayjs, info: { source: 'year' \| 'month' \| 'date' \| 'customize' }) | - | | ### 如何仅获取来自面板点击的日期? diff --git a/components/collapse/CollapsePanel.tsx b/components/collapse/CollapsePanel.tsx index 4ff984dd74..95af0ec645 100644 --- a/components/collapse/CollapsePanel.tsx +++ b/components/collapse/CollapsePanel.tsx @@ -2,8 +2,7 @@ import PanelContent from './PanelContent'; import { initDefaultProps } from '../_util/props-util'; import { collapsePanelProps } from './commonProps'; import type { ExtractPropTypes } from 'vue'; -import { defineComponent } from 'vue'; -import Transition from '../_util/transition'; +import { defineComponent, Transition } from 'vue'; import classNames from '../_util/classNames'; import devWarning from '../vc-util/devWarning'; import useConfigInject from '../config-provider/hooks/useConfigInject'; diff --git a/components/collapse/index.zh-CN.md b/components/collapse/index.zh-CN.md index e9e1c042d7..ddae33295a 100644 --- a/components/collapse/index.zh-CN.md +++ b/components/collapse/index.zh-CN.md @@ -42,6 +42,6 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sir-TK0HkWcAAA | collapsible | 是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 3.0 | | extra | 自定义渲染每个面板右上角的内容 | VNode \| slot | - | 1.5.0 | | forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | | -| header | 面板头内容 | string\|slot | 无 | | -| key | 对应 activeKey | string \| number | 无 | | +| header | 面板头内容 | string\|slot | - | | +| key | 对应 activeKey | string \| number | - | | | showArrow | 是否展示当前面板上的箭头 | boolean | `true` | | diff --git a/components/dropdown/index.zh-CN.md b/components/dropdown/index.zh-CN.md index b66ae40489..1149da0a23 100644 --- a/components/dropdown/index.zh-CN.md +++ b/components/dropdown/index.zh-CN.md @@ -22,7 +22,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5qm4S4Zgh2QAAA | 参数 | 说明 | 类型 | 默认值 | | | --- | --- | --- | --- | --- | -| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | 无 | | +| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | - | | | arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | 3.3.0 | | destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | 3.0 | | disabled | 菜单是否禁用 | boolean | - | | diff --git a/components/empty/index.tsx b/components/empty/index.tsx index 5d73982bce..ab778c9e65 100644 --- a/components/empty/index.tsx +++ b/components/empty/index.tsx @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue'; +import { defineComponent, h } from 'vue'; import type { CSSProperties, ExtractPropTypes } from 'vue'; import classNames from '../_util/classNames'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; @@ -11,9 +11,6 @@ import useConfigInject from '../config-provider/hooks/useConfigInject'; import useStyle from './style'; -const defaultEmptyImg = ; -const simpleEmptyImg = ; - interface Locale { description?: string; } @@ -40,13 +37,16 @@ const Empty = defineComponent({ return () => { const prefixCls = prefixClsRef.value; const { - image = slots.image?.() || defaultEmptyImg, + image: mergedImage = slots.image?.() || h(DefaultEmptyImg), description = slots.description?.() || undefined, imageStyle, class: className = '', ...restProps } = { ...props, ...attrs }; - + const image = + typeof mergedImage === 'function' ? (mergedImage as () => VueNode)() : mergedImage; + const isNormal = + typeof image === 'object' && 'type' in image && (image.type as any).PRESENTED_IMAGE_SIMPLE; return wrapSSR( h(DefaultEmptyImg); +Empty.PRESENTED_IMAGE_SIMPLE = () => h(SimpleEmptyImg); export default withInstall(Empty); diff --git a/components/float-button/BackTop.tsx b/components/float-button/BackTop.tsx index 6baa6daad4..7229059752 100644 --- a/components/float-button/BackTop.tsx +++ b/components/float-button/BackTop.tsx @@ -1,5 +1,5 @@ import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined'; -import { getTransitionProps, Transition } from '../_util/transition'; +import { getTransitionProps } from '../_util/transition'; import { defineComponent, nextTick, @@ -10,6 +10,7 @@ import { ref, watch, onDeactivated, + Transition, } from 'vue'; import FloatButton, { floatButtonPrefixCls } from './FloatButton'; import useConfigInject from '../config-provider/hooks/useConfigInject'; diff --git a/components/float-button/FloatButtonGroup.tsx b/components/float-button/FloatButtonGroup.tsx index 743d60e5ad..611646299d 100644 --- a/components/float-button/FloatButtonGroup.tsx +++ b/components/float-button/FloatButtonGroup.tsx @@ -1,8 +1,8 @@ -import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue'; +import { defineComponent, ref, computed, watch, onBeforeUnmount, Transition } from 'vue'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined'; import classNames from '../_util/classNames'; -import { getTransitionProps, Transition } from '../_util/transition'; +import { getTransitionProps } from '../_util/transition'; import FloatButton, { floatButtonPrefixCls } from './FloatButton'; import useConfigInject from '../config-provider/hooks/useConfigInject'; import { useProvideFloatButtonGroupContext } from './context'; diff --git a/components/float-button/index.zh-CN.md b/components/float-button/index.zh-CN.md index 589c658653..284cd6842b 100644 --- a/components/float-button/index.zh-CN.md +++ b/components/float-button/index.zh-CN.md @@ -33,11 +33,11 @@ tag: New | target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | | | badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | | -### common events +### 共同的事件 -| 事件名称 | 说明 | 回调参数 | 版本 | -| -------- | --------------------------------------- | ----------------- | ---- | -| click | Set the handler to handle `click` event | `(event) => void` | - | +| 事件名称 | 说明 | 回调参数 | 版本 | +| -------- | ----------------------------- | ----------------- | ---- | +| click | 设置处理 `click` 事件的处理器 | `(event) => void` | - | ### FloatButton.Group @@ -47,7 +47,7 @@ tag: New | trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | | | open(v-model) | 受控展开 | boolean | - | | -### FloatButton.Group Events +### FloatButton.Group 事件 | 事件名称 | 说明 | 回调参数 | 版本 | | ---------- | ---------------- | ----------------------- | ---- | diff --git a/components/icon/index.en-US.md b/components/icon/index.en-US.md index 758950f77b..7d753e2c33 100644 --- a/components/icon/index.en-US.md +++ b/components/icon/index.en-US.md @@ -122,6 +122,8 @@ See [iconfont.cn documents](http://iconfont.cn/help/detail?spm=a313x.7781069.199 ### Custom SVG Icon +#### vue cli 3 + You can import SVG icon as an vue component by using `vue cli 3` and [`vue-svg-loader`](https://www.npmjs.com/package/vue-svg-loader). `vue-svg-loader`'s `options` [reference](https://github.com/visualfanatic/vue-svg-loader). ```js @@ -149,6 +151,84 @@ export default defineComponent({ }); ``` +#### Rsbuild + +Rsbuild is a new generation of build tool, official website https://rsbuild.dev/ +Create your own `vue-svg-loader.js` file, which allows you to customize and beautify SVG, and then configure it in `rsbuild.config.ts` + +```js +// vue-svg-loader.js +/* eslint-disable */ +const { optimize } = require('svgo'); +const { version } = require('vue'); +const semverMajor = require('semver/functions/major'); + +module.exports = async function (svg) { + const callback = this.async(); + + try { + ({ data: svg } = await optimize(svg, { + path: this.resourcePath, + js2svg: { + indent: 2, + pretty: true, + }, + plugins: [ + 'convertStyleToAttrs', + 'removeDoctype', + 'removeXMLProcInst', + 'removeComments', + 'removeMetadata', + 'removeTitle', + 'removeDesc', + 'removeStyleElement', + 'removeXMLNS', + 'removeXMLProcInst', + ], + })); + } catch (error) { + callback(error); + return; + } + + if (semverMajor(version) === 2) { + svg = svg.replace('${svg}`); +}; +``` + +```js +// rsbuild.config.ts +/* eslint-disable */ +import { defineConfig } from '@rsbuild/core'; +import { pluginVue } from '@rsbuild/plugin-vue'; + +export default defineConfig({ + tools: { + bundlerChain(chain, { CHAIN_ID }) { + chain.module.rule(CHAIN_ID.RULE.SVG).exclude.add(/\.svg$/); + }, + rspack: { + module: { + rules: [ + { + test: /\.svg$/, + use: ['vue-loader', 'vue-svg-loader'], + }, + ], + }, + resolveLoader: { + alias: { + 'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'), + }, + }, + }, + }, +}); +``` + The following properties are available for the component: | Property | Description | Type | Default | diff --git a/components/icon/index.zh-CN.md b/components/icon/index.zh-CN.md index c8a02d68e5..66995e2792 100644 --- a/components/icon/index.zh-CN.md +++ b/components/icon/index.zh-CN.md @@ -119,7 +119,9 @@ export default defineComponent({ ### 自定义 SVG 图标 -如果使用 `vue cli 3`,可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。 +#### vue cli 3 + +可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。 ```js // vue.config.js @@ -146,6 +148,88 @@ export default defineComponent({ }); ``` +#### Rsbuild + +Rsbuild 是新一代构建工具,官网 https://rsbuild.dev/ + +自己实现一个 `vue-svg-loader.js` 文件,好处是可以自定义美化 svg,然后在 `rsbuild.config.ts` 中配置: + +```js +// vue-svg-loader.js +/* eslint-disable */ +const { optimize } = require('svgo'); +const { version } = require('vue'); +const semverMajor = require('semver/functions/major'); + +module.exports = async function (svg) { + const callback = this.async(); + + try { + ({ data: svg } = await optimize(svg, { + path: this.resourcePath, + js2svg: { + indent: 2, + pretty: true, + }, + plugins: [ + 'convertStyleToAttrs', + 'removeDoctype', + 'removeXMLProcInst', + 'removeComments', + 'removeMetadata', + 'removeTitle', + 'removeDesc', + 'removeStyleElement', + 'removeXMLNS', + 'removeXMLProcInst', + ], + })); + } catch (error) { + callback(error); + return; + } + + if (semverMajor(version) === 2) { + svg = svg.replace('${svg}`); +}; +``` + +```js +// rsbuild.config.ts +/* eslint-disable */ +import { defineConfig } from '@rsbuild/core'; +import { pluginVue } from '@rsbuild/plugin-vue'; + +export default defineConfig({ + tools: { + bundlerChain(chain, { CHAIN_ID }) { + chain.module + // 先给svg排除默认的规则,方便下面自定义loader + .rule(CHAIN_ID.RULE.SVG) + .exclude.add(/\.svg$/); + }, + rspack: { + module: { + rules: [ + { + test: /\.svg$/, + use: ['vue-loader', 'vue-svg-loader'], + }, + ], + }, + resolveLoader: { + alias: { + 'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'), + }, + }, + }, + }, +}); +``` + `Icon` 中的 `component` 组件的接受的属性如下: | 字段 | 说明 | 类型 | 只读值 | diff --git a/components/image/index.tsx b/components/image/index.tsx index 0e752b486b..7275f2bee6 100644 --- a/components/image/index.tsx +++ b/components/image/index.tsx @@ -13,10 +13,10 @@ export type ImageProps = Partial< ExtractPropTypes> & Omit >; -const Image = defineComponent({ +const Image = defineComponent({ name: 'AImage', inheritAttrs: false, - props: imageProps() as any, + props: imageProps(), setup(props, { slots, attrs }) { const { prefixCls, rootPrefixCls, configProvider } = useConfigInject('image', props); // Style diff --git a/components/input-number/index.zh-CN.md b/components/input-number/index.zh-CN.md index a603d4a705..3ce0b30946 100644 --- a/components/input-number/index.zh-CN.md +++ b/components/input-number/index.zh-CN.md @@ -34,7 +34,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*1uH-R5kLAMIAAA | parser | 指定从 formatter 里转换回数字的方式,和 formatter 搭配使用 | function( string): number | - | | | precision | 数值精度 | number | - | | | prefix | 带有前缀图标的 input | slot | - | 3.0 | -| size | 输入框大小 | string | 无 | | +| size | 输入框大小 | string | - | | | status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 | | step | 每次改变步数,可以为小数 | number\|string | 1 | | | stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 | diff --git a/components/input-number/src/InputNumber.tsx b/components/input-number/src/InputNumber.tsx index 811b8eeef5..9fa9a7d46e 100644 --- a/components/input-number/src/InputNumber.tsx +++ b/components/input-number/src/InputNumber.tsx @@ -395,6 +395,11 @@ export default defineComponent({ } }; + // Solve the issue of the event triggering sequence when entering numbers in chinese input (Safari) + const onBeforeInput = () => { + userTypingRef.value = true; + }; + const onKeyDown: KeyboardEventHandler = event => { const { which } = event; userTypingRef.value = true; @@ -577,6 +582,7 @@ export default defineComponent({ onBlur={onBlur} onCompositionstart={onCompositionStart} onCompositionend={onCompositionEnd} + onBeforeinput={onBeforeInput} /> diff --git a/components/input-number/style/index.tsx b/components/input-number/style/index.tsx index d119e7d663..e363f0772c 100644 --- a/components/input-number/style/index.tsx +++ b/components/input-number/style/index.tsx @@ -263,6 +263,10 @@ const genInputNumberStyles: GenerateStyle = (token: InputNumbe [`${componentCls}-handler-wrap`]: { display: 'none', }, + + [`${componentCls}-input`]: { + color: 'inherit', + }, }, [` diff --git a/components/input/index.en-US.md b/components/input/index.en-US.md index a57cd983c2..aa5837ea2b 100644 --- a/components/input/index.en-US.md +++ b/components/input/index.en-US.md @@ -29,7 +29,7 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca | id | The ID for input | string | | | | maxlength | max length | number | | 1.5.0 | | prefix | The prefix icon for the Input. | string\|slot | | | -| showCount | Whether show text count | boolean | false | 3.0 | +| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string | false | 3.0 | | status | Set validation status | 'error' \| 'warning' | - | 3.3.0 | | size | The size of the input box. Note: in the context of a form, the `middle` size is used. Available: `large` `middle` `small` | string | - | | | suffix | The suffix icon for the Input. | string\|slot | | | @@ -52,7 +52,7 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca | allowClear | allow to remove input content with clear icon | boolean | | 1.5.0 | | | autosize | Height autosize feature, can be set to `true | false`or an object`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | | | defaultValue | The initial input content | string | | | | -| showCount | Whether show text count | boolean | false | | | +| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string | false | | | | value(v-model) | The input content value | string | | | | ### TextArea Events diff --git a/components/input/index.zh-CN.md b/components/input/index.zh-CN.md index 06489389d4..45e103f9e6 100644 --- a/components/input/index.zh-CN.md +++ b/components/input/index.zh-CN.md @@ -30,7 +30,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA | id | 输入框的 id | string | | | | maxlength | 最大长度 | number | | 1.5.0 | | prefix | 带有前缀图标的 input | string\|slot | | | -| showCount | 是否展示字数 | boolean | false | 3.0 | +| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | 3.0 | | status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 | | size | 控件大小。注:标准表单内的输入框大小限制为 `middle`。可选 `large` `middle` `small` | string | - | | | suffix | 带有后缀图标的 input | string\|slot | | | @@ -53,7 +53,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA | allowClear | 可以点击清除图标删除内容 | boolean | | 1.5.0 | | | autosize | 自适应内容高度,可设置为 `true | false` 或对象:`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | | | defaultValue | 输入框默认内容 | string | | | | -| showCount | 是否展示字数 | boolean | false | | | +_| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | | |_ | value(v-model) | 输入框内容 | string | | | | ### TextArea 事件 diff --git a/components/mentions/demo/placement.vue b/components/mentions/demo/placement.vue index e2bbb07b74..da0b87c571 100644 --- a/components/mentions/demo/placement.vue +++ b/components/mentions/demo/placement.vue @@ -3,7 +3,7 @@ order: 4 title: zh-CN: 向上展开 - en-US: Placemen + en-US: Placement --- ## zh-CN diff --git a/components/menu/src/InlineSubMenuList.tsx b/components/menu/src/InlineSubMenuList.tsx index 29794e8be9..7b9cb1f33b 100644 --- a/components/menu/src/InlineSubMenuList.tsx +++ b/components/menu/src/InlineSubMenuList.tsx @@ -1,5 +1,4 @@ -import { computed, defineComponent, ref, watch } from 'vue'; -import Transition from '../../_util/transition'; +import { computed, Transition, defineComponent, ref, watch } from 'vue'; import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext'; import type { MenuMode } from './interface'; import SubMenuList from './SubMenuList'; diff --git a/components/message/useMessage.tsx b/components/message/useMessage.tsx index e4e929eb28..f1ae5325f3 100644 --- a/components/message/useMessage.tsx +++ b/components/message/useMessage.tsx @@ -47,7 +47,9 @@ const Holder = defineComponent({ 'rtl', 'transitionName', 'onAllRemoved', - ] as any, + 'animation', + 'staticGetContainer', + ], setup(props, { expose }) { const { getPrefixCls, getPopupContainer } = useConfigInject('message', props); diff --git a/components/modal/index.zh-CN.md b/components/modal/index.zh-CN.md index 931649b1bc..103885923b 100644 --- a/components/modal/index.zh-CN.md +++ b/components/modal/index.zh-CN.md @@ -19,14 +19,14 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | -| afterClose | Modal 完全关闭后的回调 | function | 无 | | +| afterClose | Modal 完全关闭后的回调 | function | - | | | bodyStyle | Modal body 样式 | object | {} | | | cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#api) | - | | | cancelText | 取消按钮文字 | string\| slot | 取消 | | | centered | 垂直居中展示 Modal | boolean | `false` | | | closable | 是否显示右上角的关闭按钮 | boolean | true | | | closeIcon | 自定义关闭图标 | VNode \| slot | - | | -| confirmLoading | 确定按钮 loading | boolean | 无 | | +| confirmLoading | 确定按钮 loading | boolean | - | | | destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | | | footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 | | | forceRender | 强制渲染 Modal | boolean | false | | @@ -38,8 +38,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA | okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#api) | - | | | okText | 确认按钮文字 | string\|slot | 确定 | | | okType | 确认按钮类型 | string | primary | | -| title | 标题 | string\|slot | 无 | | -| open(v-model) | 对话框是否可见 | boolean | 无 | | +| title | 标题 | string\|slot | - | | +| open(v-model) | 对话框是否可见 | boolean | - | | | width | 宽度 | string\|number | 520 | | | wrapClassName | 对话框外层容器的类名 | string | - | | | zIndex | 设置 Modal 的 `z-index` | number | 1000 | | @@ -76,7 +76,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA | centered | 垂直居中展示 Modal | boolean | `false` | | | class | 容器类名 | string | - | | | closable | 是否显示右上角的关闭按钮 | boolean | `false` | | -| content | 内容 | string \|VNode \|function() | 无 | | +| content | 内容 | string \|VNode \|function() | - | | | footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer: null` | string \|VNode \|function() | - | 4.0.0 | | icon | 自定义图标(1.14.0 新增) | VNode \| ()=>VNode | - | | | keyboard | 是否支持键盘 esc 关闭 | boolean | true | | @@ -85,12 +85,12 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA | okButtonProps | ok 按钮 props | [ButtonProps](/components/button) | - | | | okText | 确认按钮文字 | string | 确定 | | | okType | 确认按钮类型 | string | primary | | -| title | 标题 | string\|VNode \|function() | 无 | | +| title | 标题 | string\|VNode \|function() | - | | | width | 宽度 | string\|number | 416 | | | wrapClassName | 对话框外层容器的类名 | string | - | 3.2.3 | | zIndex | 设置 Modal 的 `z-index` | number | 1000 | | -| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | | -| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | | +| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | | +| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | | 以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。 diff --git a/components/popconfirm/index.zh-CN.md b/components/popconfirm/index.zh-CN.md index 22d4e23542..df402b00b7 100644 --- a/components/popconfirm/index.zh-CN.md +++ b/components/popconfirm/index.zh-CN.md @@ -27,7 +27,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HrFtQ6jJJFQAAA | okText | 确认按钮文字 | string\|slot | 确定 | | | okType | 确认按钮类型 | string | primary | | | showCancel | 是否显示取消按钮 | boolean | true | 3.0 | -| title | 确认框的描述 | string\|slot | 无 | | +| title | 确认框的描述 | string\|slot | - | | | description | 确认内容的详细描述 | string\|slot | - | 4.0 | | open (v-model) | 是否显示 | boolean | - | 4.0 | diff --git a/components/segmented/index.zh-CN.md b/components/segmented/index.zh-CN.md index 91b1b03a5c..8d5068da5d 100644 --- a/components/segmented/index.zh-CN.md +++ b/components/segmented/index.zh-CN.md @@ -21,7 +21,7 @@ tag: New | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | -| block | 将宽度调整为父元素宽度的选项 | boolean | 无 | | +| block | 将宽度调整为父元素宽度的选项 | boolean | - | | | disabled | 是否禁用 | boolean | false | | | options | 数据化配置选项内容 | string[] \| number[] \| SegmentedOption[] | [] | | | size | 控件尺寸 | `large` \| `middle` \| `small` | - | | diff --git a/components/select/__tests__/index.test.js b/components/select/__tests__/index.test.js index e169e107ff..46ee2e46f2 100644 --- a/components/select/__tests__/index.test.js +++ b/components/select/__tests__/index.test.js @@ -159,6 +159,52 @@ describe('Select', () => { }, 500); }); + it('The select trigger should be blur when the panel is closed.', async () => { + const wrapper = mount( + { + render() { + return ( + ; + }} + /> + ); + }, + }, + { + sync: false, + attachTo: 'body', + }, + ); + await asyncExpect(async () => { + await wrapper.find('.ant-select-selector').trigger('mousedown'); + await wrapper.find('.ant-select-selection-search-input').trigger('focus'); + }); + + await asyncExpect(async () => { + const el = wrapper.find('.ant-select'); + + expect(el.classes()).toContain('ant-select-focused'); + $$('#dropdownRenderInput')[0].focus(); + + expect(el.classes()).toContain('ant-select-focused'); + + document.body.dispatchEvent( + new MouseEvent('mousedown', { + bubbles: true, + cancelable: true, + view: window, + }), + ); + }, 100); + + await asyncExpect(async () => { + const el = wrapper.find('.ant-select'); + expect(el.classes()).not.toContain('ant-select-focused'); + }, 200); + }); + describe('Select Custom Icons', () => { it('should support customized icons', () => { const wrapper = mount({ diff --git a/components/select/index.en-US.md b/components/select/index.en-US.md index 136217e541..4dda321cd0 100644 --- a/components/select/index.en-US.md +++ b/components/select/index.en-US.md @@ -63,7 +63,7 @@ Select component to select value from options. | searchValue | The current input "search" text | string | - | | | showArrow | Whether to show the drop-down arrow | boolean | single:true, multiple:false | | | showSearch | Whether select is searchable | boolean | single:false, multiple:true | | -| size | Size of Select input. `default` `large` `small` | string | default | | +| size | Size of Select input. `middle` `large` `small` | string | middle | | | status | Set validation status | 'error' \| 'warning' | - | 3.3.0 | | suffixIcon | The custom suffix icon | VNode \| slot | - | | | tagRender | Customize tag render, only applies when `mode` is set to `multiple` or `tags` | slot \| (props) => any | - | | diff --git a/components/select/index.zh-CN.md b/components/select/index.zh-CN.md index 4de3bf8ae4..bb8be2a133 100644 --- a/components/select/index.zh-CN.md +++ b/components/select/index.zh-CN.md @@ -63,7 +63,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5oPiTqPxGAUAAA | searchValue | 控制搜索文本 | string | - | | | showArrow | 是否显示下拉小箭头 | boolean | 单选为 true,多选为 false | | | showSearch | 配置是否可搜索 | boolean | 单选为 false,多选为 true | | -| size | 选择框大小,可选 `large` `small` | string | default | | +| size | 选择框大小,可选 `middle` `large` `small` | string | middle | | | status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 | | suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - | | | tagRender | 自定义 tag 内容 render,仅在 `mode` 为 `multiple` 或 `tags` 时生效 | slot \| (props) => any | - | 3.0 | @@ -111,7 +111,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5oPiTqPxGAUAAA | 参数 | 说明 | 类型 | 默认值 | | ----- | ---- | ------------------------- | ------ | | key | | string | - | -| label | 组名 | string\|function(h)\|slot | 无 | +| label | 组名 | string\|function(h)\|slot | - | ## FAQ diff --git a/components/select/style/multiple.ts b/components/select/style/multiple.ts index 70e4aba00b..ee38f0b8e7 100644 --- a/components/select/style/multiple.ts +++ b/components/select/style/multiple.ts @@ -213,7 +213,7 @@ export default function genMultipleStyle(token: SelectToken): CSSInterpolation { [`${componentCls}-multiple${componentCls}-sm`]: { [`${componentCls}-selection-placeholder`]: { insetInlineStart: token.controlPaddingHorizontalSM - token.lineWidth, - insetInlineEnd: 'auto', + insetInlineEnd: token.controlPaddingHorizontalSM - token.lineWidth, }, // https://github.com/ant-design/ant-design/issues/29559 diff --git a/components/slider/demo/event.vue b/components/slider/demo/event.vue index a1733cb72a..67b1f5df3a 100644 --- a/components/slider/demo/event.vue +++ b/components/slider/demo/event.vue @@ -17,8 +17,8 @@ The `onChange` callback function will fire when the user changes the slider's va