From 5b3ade8980cb2332451cd44831c4d25da5f08902 Mon Sep 17 00:00:00 2001 From: lyn <76365499@qq.com> Date: Fri, 25 Nov 2022 15:47:23 +0800 Subject: [PATCH 1/7] docs(select): docs update (#6118) --- components/select/index.en-US.md | 4 ++-- components/select/index.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/select/index.en-US.md b/components/select/index.en-US.md index ca27c7386..88969564b 100644 --- a/components/select/index.en-US.md +++ b/components/select/index.en-US.md @@ -59,8 +59,8 @@ Select component to select value from options. | placeholder | Placeholder of select | string\|slot | - | | | removeIcon | The custom remove icon | VNode \| slot | - | | | searchValue | The current input "search" text | string | - | | -| showArrow | Whether to show the drop-down arrow | boolean | true | | -| showSearch | Whether show search input in single mode. | boolean | false | | +| 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 | | | 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 3d9da7c3b..7cc33f829 100644 --- a/components/select/index.zh-CN.md +++ b/components/select/index.zh-CN.md @@ -59,8 +59,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg | placeholder | 选择框默认文字 | string\|slot | - | | | removeIcon | 自定义的多选框清除图标 | VNode \| slot | - | | | searchValue | 控制搜索文本 | string | - | | -| showArrow | 是否显示下拉小箭头 | boolean | true | | -| showSearch | 使单选模式可搜索 | boolean | false | | +| showArrow | 是否显示下拉小箭头 | boolean | 单选为true,多选为false | | +| showSearch | 配置是否可搜索 | boolean | 单选为false,多选为true | | | size | 选择框大小,可选 `large` `small` | string | default | | | suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - | | | tagRender | 自定义 tag 内容 render,仅在 `mode` 为 `multiple` 或 `tags` 时生效 | slot \| (props) => any | - | 3.0 | From 7ea18a8287beacff25c4349fd922839a22072de5 Mon Sep 17 00:00:00 2001 From: Konv Suu <82451257+kovsu@users.noreply.github.com> Date: Sun, 11 Dec 2022 14:49:02 +0800 Subject: [PATCH 2/7] fix: notification onClose event runs repeatedly (#6150) --- components/vc-notification/Notice.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/vc-notification/Notice.tsx b/components/vc-notification/Notice.tsx index 33fe20649..cf9eee1d5 100644 --- a/components/vc-notification/Notice.tsx +++ b/components/vc-notification/Notice.tsx @@ -46,9 +46,10 @@ export default defineComponent({ ] as any, setup(props, { attrs, slots }) { let closeTimer: any; - const duration = computed(() => (props.duration === undefined ? 1.5 : props.duration)); + let isUnMounted = false; + const duration = computed(() => (props.duration === undefined ? 4.5 : props.duration)); const startCloseTimer = () => { - if (duration.value) { + if (duration.value && !isUnMounted) { closeTimer = setTimeout(() => { close(); }, duration.value * 1000); @@ -79,6 +80,7 @@ export default defineComponent({ startCloseTimer(); }); onUnmounted(() => { + isUnMounted = true; clearCloseTimer(); }); From 8a0c8a8fb12d152a4761a7f4ecf32bb8dec6dbbe Mon Sep 17 00:00:00 2001 From: "M.Wang" Date: Thu, 15 Dec 2022 10:28:33 +0800 Subject: [PATCH 3/7] fix(vc-slick): #6100 - Fix content responsiveness in carousel component slot. (#6149) * fix(vc-slick): #6100 - Fix content responsiveness in carousel component slot. * feat(_util) add deepCloneElement function --- components/_util/vnode.ts | 22 ++++++++++++++++++++-- components/vc-slick/track.jsx | 10 +++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/components/_util/vnode.ts b/components/_util/vnode.ts index c770abc11..505bb638d 100644 --- a/components/_util/vnode.ts +++ b/components/_util/vnode.ts @@ -3,11 +3,12 @@ import type { VNode, VNodeProps } from 'vue'; import { cloneVNode } from 'vue'; import warning from './warning'; import type { RefObject } from './createRef'; +type NodeProps = Record & + Omit & { ref?: VNodeProps['ref'] | RefObject }; export function cloneElement( vnode: VNode | VNode[], - nodeProps: Record & - Omit & { ref?: VNodeProps['ref'] | RefObject } = {}, + nodeProps: NodeProps = {}, override = true, mergeRef = false, ): VNode { @@ -29,3 +30,20 @@ export function cloneElement( export function cloneVNodes(vnodes, nodeProps = {}, override = true) { return vnodes.map(vnode => cloneElement(vnode, nodeProps, override)); } + +export function deepCloneElement( + vnode: VNode | VNode[], + nodeProps: NodeProps = {}, + override = true, + mergeRef = false, +) { + if (Array.isArray(vnode)) { + return vnode.map(item => deepCloneElement(item, nodeProps, override, mergeRef)); + } else { + const cloned = cloneElement(vnode, nodeProps, override, mergeRef); + if (Array.isArray(cloned.children)) { + cloned.children = deepCloneElement(cloned.children as VNode[]); + } + return cloned; + } +} diff --git a/components/vc-slick/track.jsx b/components/vc-slick/track.jsx index 5616172d9..a8665e401 100644 --- a/components/vc-slick/track.jsx +++ b/components/vc-slick/track.jsx @@ -1,8 +1,8 @@ import { createVNode } from 'vue'; import classnames from '../_util/classNames'; -import { cloneElement } from '../_util/vnode'; import { flattenChildren } from '../_util/props-util'; import { lazyStartIndex, lazyEndIndex, getPreClones } from './utils/innerSliderUtils'; +import { deepCloneElement } from '../_util/vnode'; // given specifications/props for a slide, fetch all the classes that need to be applied to the slide const getSlideClasses = spec => { @@ -84,7 +84,6 @@ const renderSlides = function (spec, children) { const childrenCount = children.length; const startIndex = lazyStartIndex(spec); const endIndex = lazyEndIndex(spec); - children.forEach((elem, index) => { let child; const childOnClickOptions = { @@ -105,7 +104,7 @@ const renderSlides = function (spec, children) { let slideClasses = getSlideClasses({ ...spec, index }); // push a cloned element of the desired slide slides.push( - cloneElement(child, { + deepCloneElement(child, { key: 'original' + getKey(child, index), tabindex: '-1', 'data-index': index, @@ -131,7 +130,7 @@ const renderSlides = function (spec, children) { } slideClasses = getSlideClasses({ ...spec, index: key }); preCloneSlides.push( - cloneElement(child, { + deepCloneElement(child, { key: 'precloned' + getKey(child, key), class: classnames(slideClasses, slideClass), tabindex: '-1', @@ -155,7 +154,7 @@ const renderSlides = function (spec, children) { } slideClasses = getSlideClasses({ ...spec, index: key }); postCloneSlides.push( - cloneElement(child, { + deepCloneElement(child, { key: 'postcloned' + getKey(child, key), tabindex: '-1', 'data-index': key, @@ -182,6 +181,7 @@ const renderSlides = function (spec, children) { const Track = (_, { attrs, slots }) => { const slides = renderSlides(attrs, flattenChildren(slots?.default())); + // const slides = renderSlides(attrs, slots?.default); const { onMouseenter, onMouseover, onMouseleave } = attrs; const mouseEvents = { onMouseenter, onMouseover, onMouseleave }; const trackProps = { From 75c65e094fc74b0fa4ee6937730d756ab1d6a926 Mon Sep 17 00:00:00 2001 From: tarasovsn Date: Thu, 15 Dec 2022 05:54:20 +0300 Subject: [PATCH 4/7] Fixed some errors in generator-types (#6095) Co-authored-by: starasov --- antd-tools/generator-types/index.js | 31 +++---- antd-tools/generator-types/src/formatter.ts | 18 +++- antd-tools/generator-types/src/index.ts | 91 +++++++++++++++------ antd-tools/generator-types/src/parser.ts | 8 +- antd-tools/generator-types/src/type.ts | 7 +- antd-tools/generator-types/src/utils.ts | 4 +- 6 files changed, 103 insertions(+), 56 deletions(-) diff --git a/antd-tools/generator-types/index.js b/antd-tools/generator-types/index.js index 650a7b8ee..8a456e0a1 100644 --- a/antd-tools/generator-types/index.js +++ b/antd-tools/generator-types/index.js @@ -3,18 +3,21 @@ const pkg = require('../../package.json'); const { parseAndWrite } = require('./lib/index.js'); const rootPath = path.resolve(__dirname, '../../'); -try { - parseAndWrite({ - version: pkg.version, - name: 'ant-design-vue', - path: path.resolve(rootPath, './components'), - // default match lang - test: /en-US\.md/, - outputDir: path.resolve(rootPath, './vetur'), - tagPrefix: 'a-', +parseAndWrite({ + version: pkg.version, + name: 'ant-design-vue', + path: path.resolve(rootPath, './components'), + typingsPath: path.resolve(rootPath, './typings/global.d.ts'), + // default match lang + test: /en-US\.md/, + outputDir: path.resolve(rootPath, './vetur'), + tagPrefix: 'a-', +}) + .then(result => { + // eslint-disable-next-line no-console + console.log(`generator types success: ${result} tags generated`); + }) + .catch(error => { + console.error('generator types error', error); + return Promise.reject(error); }); - // eslint-disable-next-line no-console - console.log('generator types success'); -} catch (e) { - console.error('generator types error', e); -} diff --git a/antd-tools/generator-types/src/formatter.ts b/antd-tools/generator-types/src/formatter.ts index 5a17d0082..722077ecf 100644 --- a/antd-tools/generator-types/src/formatter.ts +++ b/antd-tools/generator-types/src/formatter.ts @@ -34,14 +34,19 @@ function parserProps(tag: VueTag, line: any) { }); } -export function formatter(articals: Articals, componentName: string, tagPrefix = '') { +export function formatter( + articals: Articals, + componentName: string, + kebabComponentName: string, + tagPrefix = '', +) { if (!articals.length) { return; } const tags: VueTag[] = []; const tag: VueTag = { - name: getComponentName(componentName, tagPrefix), + name: kebabComponentName, slots: [], events: [], attributes: [], @@ -80,9 +85,13 @@ export function formatter(articals: Articals, componentName: string, tagPrefix = } // 额外的子组件 - if (tableTitle.includes(componentName) && !tableTitle.includes('events')) { + if ( + tableTitle.includes(componentName) && + !tableTitle.includes('events') && + !tableTitle.includes('()') + ) { const childTag: VueTag = { - name: getComponentName(tableTitle.replace('.', ''), tagPrefix), + name: getComponentName(tableTitle.replaceAll('.', '').replaceAll('/', ''), tagPrefix), slots: [], events: [], attributes: [], @@ -93,6 +102,7 @@ export function formatter(articals: Articals, componentName: string, tagPrefix = tags.push(childTag); return; } + // 额外的子组件事件 if (tableTitle.includes(componentName) && tableTitle.includes('events')) { const childTagName = getComponentName( diff --git a/antd-tools/generator-types/src/index.ts b/antd-tools/generator-types/src/index.ts index 3536a8808..c500b38e1 100644 --- a/antd-tools/generator-types/src/index.ts +++ b/antd-tools/generator-types/src/index.ts @@ -1,52 +1,91 @@ import glob from 'fast-glob'; -import { join, dirname } from 'path'; +import { dirname, join } from 'path'; import { mdParser } from './parser'; import { formatter } from './formatter'; import { genWebTypes } from './web-types'; -import { readFileSync, outputFileSync } from 'fs-extra'; +import { outputFileSync, readFileSync } from 'fs-extra'; import type { Options, VueTag } from './type'; -import { normalizePath, getComponentName } from './utils'; -import { genVeturTags, genVeturAttributes } from './vetur'; +import { getComponentName, normalizePath, toKebabCase } from './utils'; +import { genVeturAttributes, genVeturTags } from './vetur'; -async function readMarkdown(options: Options) { - // const mds = await glob(normalizePath(`${options.path}/**/*.md`)) - const mds = await glob(normalizePath(`${options.path}/**/*.md`)); - return mds +async function readMarkdown(options: Options): Promise> { + const mdPaths = await glob(normalizePath(`${options.path}/**/*.md`)); + const data = mdPaths .filter(md => options.test.test(md)) .map(path => { const docPath = dirname(path); - const componentName = docPath.substring(docPath.lastIndexOf('/') + 1); - return { - componentName: getComponentName(componentName || ''), - md: readFileSync(path, 'utf-8'), - }; - }); + const kebabComponentName = + options.tagPrefix + docPath.substring(docPath.lastIndexOf('/') + 1) || ''; + const componentName = getComponentName(docPath.substring(docPath.lastIndexOf('/') + 1) || ''); + const fileContent = readFileSync(path, 'utf-8'); + return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix); + }) + .filter(item => item) as VueTag[][]; + const tags: Map = new Map(); + data.flatMap(item => item).forEach(mergedTag => mergeTag(tags, mergedTag)); + return tags; } -export async function parseAndWrite(options: Options) { +function readTypings(options: Options): Map { + const tags: Map = new Map(); + const fileContent = readFileSync(options.typingsPath, 'utf-8'); + fileContent + .split('\n') + .filter(line => line && line.includes('typeof')) + .map(line => { + const l = line.trim(); + return toKebabCase(l.substring(0, l.indexOf(':'))); + }) + .forEach(tagName => + tags.set(tagName, { + name: tagName, + slots: [], + events: [], + attributes: [], + }), + ); + return tags; +} + +function mergeTag(tags: Map, mergedTag: VueTag) { + const tagName = mergedTag.name; + const vueTag = tags.get(tagName); + if (vueTag) { + vueTag.slots = [...vueTag.slots, ...mergedTag.slots]; + vueTag.events = [...vueTag.events, ...mergedTag.events]; + vueTag.attributes = [...vueTag.attributes, ...mergedTag.attributes]; + } else { + tags.set(tagName, mergedTag); + } +} + +function mergeTags(mergedTagsArr: Map[]): VueTag[] { + if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()]; + const tags: Map = new Map(); + if (mergedTagsArr.length === 0) return []; + mergedTagsArr.forEach(mergedTags => { + mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag)); + }); + return [...tags.values()]; +} + +export async function parseAndWrite(options: Options): Promise { if (!options.outputDir) { throw new Error('outputDir can not be empty.'); } - - const docs = await readMarkdown(options); - const datas = docs - .map(doc => formatter(mdParser(doc.md), doc.componentName, options.tagPrefix)) - .filter(item => item) as VueTag[][]; - const tags: VueTag[] = []; - datas.forEach(arr => { - tags.push(...arr); - }); - + const tagsFromMarkdown = await readMarkdown(options); + const tagsFromTypings = await readTypings(options); + const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]); const webTypes = genWebTypes(tags, options); const veturTags = genVeturTags(tags); const veturAttributes = genVeturAttributes(tags); - outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2)); outputFileSync( join(options.outputDir, 'attributes.json'), JSON.stringify(veturAttributes, null, 2), ); outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2)); + return tags.length; } export default { parseAndWrite }; diff --git a/antd-tools/generator-types/src/parser.ts b/antd-tools/generator-types/src/parser.ts index 964b09516..5a20559e5 100644 --- a/antd-tools/generator-types/src/parser.ts +++ b/antd-tools/generator-types/src/parser.ts @@ -27,7 +27,7 @@ function readLine(input: string) { function splitTableLine(line: string) { line = line.replace(/\\\|/g, 'JOIN'); - const items = line.split('|').map(item => item.trim().replace('JOIN', '|')); + const items = line.split('|').map(item => item.trim().replaceAll('JOIN', '|')); // remove pipe character on both sides items.pop(); @@ -77,11 +77,6 @@ export function mdParser(input: string): Articals { const artical = []; let start = 0; const end = input.length; - // artical.push({ - // type: 'title', - // content: title, - // level: 0, - // }); while (start < end) { const target = input.substr(start); @@ -108,6 +103,5 @@ export function mdParser(input: string): Articals { } } - // artical[0].content = title return artical; } diff --git a/antd-tools/generator-types/src/type.ts b/antd-tools/generator-types/src/type.ts index 503c9cf56..faf2ed939 100644 --- a/antd-tools/generator-types/src/type.ts +++ b/antd-tools/generator-types/src/type.ts @@ -28,9 +28,9 @@ export type VueAttribute = { export type VueTag = { name: string; - slots?: VueSlot[]; - events?: VueEvent[]; - attributes?: VueAttribute[]; + slots: VueSlot[]; + events: VueEvent[]; + attributes: VueAttribute[]; description?: string; }; @@ -56,6 +56,7 @@ export type VeturResult = { export type Options = { name: string; path: PathLike; + typingsPath: PathLike; test: RegExp; version: string; outputDir?: string; diff --git a/antd-tools/generator-types/src/utils.ts b/antd-tools/generator-types/src/utils.ts index 4b0aa3f80..50ef2ab34 100644 --- a/antd-tools/generator-types/src/utils.ts +++ b/antd-tools/generator-types/src/utils.ts @@ -1,6 +1,6 @@ // myName -> my-name -export function toKebabCase(input: string): string { - return input.replace(/[A-Z]/g, (val, index) => (index === 0 ? '' : '-') + val.toLowerCase()); +export function toKebabCase(camel: string): string { + return camel.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase(); } // name `v2.0.0` -> name From c8b7848f99dd820cedf24575d7ea1110041d4f09 Mon Sep 17 00:00:00 2001 From: lyn <76365499@qq.com> Date: Tue, 17 Jan 2023 16:51:39 +0800 Subject: [PATCH 5/7] docs(date-picker): docs update (#6175) * Update index.zh-CN.md * Update index.en-US.md --- components/date-picker/index.en-US.md | 2 +- components/date-picker/index.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md index 094beb13d..e1887c776 100644 --- a/components/date-picker/index.en-US.md +++ b/components/date-picker/index.en-US.md @@ -171,7 +171,7 @@ The following APIs are shared by DatePicker, RangePicker. | disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | | | format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting | string \| string\[] | `YYYY-MM-DD HH:mm:ss` | | | ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | -| renderExtraFooter | Render extra footer in panel | v-slot:renderExtraFooter | - | | +| renderExtraFooter | Render extra footer in panel | v-slot:renderExtraFooter="mode" | - | | | separator | Set separator between inputs | string \| v-slot:separator | `` | | | showTime | To provide an additional time selection | object \| boolean | [TimePicker Options](/components/time-picker/#API) | | | showTime.defaultValue | To set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index b1ff2a057..3cf3cdfc8 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -172,7 +172,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/RT_USzA48/DatePicker.svg | disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | | | format | 展示的日期格式 | string | `YYYY-MM-DD HH:mm:ss` | | | ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | | -| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - | | +| renderExtraFooter | 在面板中添加额外的页脚 | v-slot:renderExtraFooter="mode" | - | | | separator | 设置分隔符 | string \| v-slot:separator | `` | | | showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker/#API) | | | showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [dayjs](https://day.js.org/)\[] | \[dayjs(), dayjs()] | | From 034f71c005f3a03a9afae1928e776d968e8edfe2 Mon Sep 17 00:00:00 2001 From: DMQ <420025381@qq.com> Date: Tue, 17 Jan 2023 16:52:16 +0800 Subject: [PATCH 6/7] fix: set the correct activce classname for stickyScrollBar (#6169) --- components/vc-table/stickyScrollBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/vc-table/stickyScrollBar.tsx b/components/vc-table/stickyScrollBar.tsx index 5579ab2db..4f3967c78 100644 --- a/components/vc-table/stickyScrollBar.tsx +++ b/components/vc-table/stickyScrollBar.tsx @@ -230,7 +230,7 @@ export default defineComponent({ onMousedown={onMouseDown} ref={scrollBarRef} class={classNames(`${prefixCls}-sticky-scroll-bar`, { - [`${prefixCls}-sticky-scroll-bar-active`]: isActive, + [`${prefixCls}-sticky-scroll-bar-active`]: isActive.value, })} style={{ width: `${scrollBarWidth.value}px`, From 058bc3622a275d4eee7898158a6f467cb34cfe19 Mon Sep 17 00:00:00 2001 From: Nguyen Ba Hung Date: Tue, 17 Jan 2023 15:55:16 +0700 Subject: [PATCH 7/7] doc: Add "format" prop for time-picker demo (#6197) The `format` prop is used to format the display value of the time-picker. Reference from AntDesign official docs: https://github.com/ant-design/ant-design/blob/master/components/time-picker/demo/hide-column.tsx --- components/form/demo/time-related-controls.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/form/demo/time-related-controls.vue b/components/form/demo/time-related-controls.vue index 0e691c6d1..1bd71b111 100644 --- a/components/form/demo/time-related-controls.vue +++ b/components/form/demo/time-related-controls.vue @@ -56,7 +56,7 @@ or use `valueFormat` to format. /> - +