refactor: cascader checkbox collapse comment description divider by ts

pull/2992/head
tanjinzhou 2020-10-14 17:57:38 +08:00
parent c732d09745
commit db31c526d9
18 changed files with 266 additions and 185 deletions

View File

@ -3,7 +3,7 @@ import Select from '../select';
import { Group, Button } from '../radio'; import { Group, Button } from '../radio';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { VueNode } from 'components/_util/type'; import { VueNode } from '../_util/type';
const { Option } = Select; const { Option } = Select;

View File

@ -1,5 +1,5 @@
import { App, defineComponent, inject, provide, PropType } from 'vue'; import { App, inject, provide, PropType, defineComponent, CSSProperties } from 'vue';
import PropTypes, { withUndefined } from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import VcCascader from '../vc-cascader'; import VcCascader from '../vc-cascader';
import arrayTreeFilter from 'array-tree-filter'; import arrayTreeFilter from 'array-tree-filter';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
@ -23,7 +23,8 @@ import BaseMixin from '../_util/BaseMixin';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import warning from '../_util/warning'; import warning from '../_util/warning';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { tuple, VueNode } from 'components/_util/type'; import { tuple, VueNode } from '../_util/type';
import { RenderEmptyHandler } from '../config-provider/renderEmpty';
export interface CascaderOptionType { export interface CascaderOptionType {
value?: string | number; value?: string | number;
@ -31,7 +32,7 @@ export interface CascaderOptionType {
disabled?: boolean; disabled?: boolean;
isLeaf?: boolean; isLeaf?: boolean;
loading?: boolean; loading?: boolean;
children?: Array<CascaderOptionType>; children?: CascaderOptionType[];
[key: string]: any; [key: string]: any;
} }
@ -90,7 +91,7 @@ function noop() {}
const CascaderProps = { const CascaderProps = {
/** 可选项数据源 */ /** 可选项数据源 */
options: { type: Array as PropType<CascaderOptionType>, default: [] }, options: { type: Array as PropType<CascaderOptionType[]>, default: [] },
/** 默认的选中项 */ /** 默认的选中项 */
defaultValue: PropTypes.array, defaultValue: PropTypes.array,
/** 指定选中项 */ /** 指定选中项 */
@ -116,8 +117,8 @@ const CascaderProps = {
/** 是否支持清除*/ /** 是否支持清除*/
allowClear: PropTypes.looseBool.def(true), allowClear: PropTypes.looseBool.def(true),
showSearch: { showSearch: {
type: [Boolean, Object] as PropType<ShowSearchType>, type: [Boolean, Object] as PropType<boolean | ShowSearchType | undefined>,
default: undefined, default: undefined as PropType<boolean | ShowSearchType | undefined>,
}, },
notFoundContent: PropTypes.VNodeChild, notFoundContent: PropTypes.VNodeChild,
loadData: PropTypes.func, loadData: PropTypes.func,
@ -143,8 +144,6 @@ const CascaderProps = {
'onUpdate:value': PropTypes.func, 'onUpdate:value': PropTypes.func,
}; };
type CascaderPropsTypes = typeof CascaderProps;
// We limit the filtered item count by default // We limit the filtered item count by default
const defaultLimit = 50; const defaultLimit = 50;
@ -169,7 +168,7 @@ function defaultSortFilteredOption(
return a.findIndex(callback) - b.findIndex(callback); return a.findIndex(callback) - b.findIndex(callback);
} }
function getFilledFieldNames(props: CascaderPropsTypes) { function getFilledFieldNames(props: any) {
const fieldNames = (props.fieldNames || {}) as FieldNamesType; const fieldNames = (props.fieldNames || {}) as FieldNamesType;
const names: FilledFieldNamesType = { const names: FilledFieldNamesType = {
children: fieldNames.children || 'children', children: fieldNames.children || 'children',
@ -181,7 +180,7 @@ function getFilledFieldNames(props: CascaderPropsTypes) {
function flattenTree( function flattenTree(
options: CascaderOptionType[], options: CascaderOptionType[],
props: CascaderPropsTypes, props: any,
ancestor: CascaderOptionType[] = [], ancestor: CascaderOptionType[] = [],
) { ) {
const names: FilledFieldNamesType = getFilledFieldNames(props); const names: FilledFieldNamesType = getFilledFieldNames(props);
@ -201,7 +200,7 @@ function flattenTree(
const defaultDisplayRender = ({ labels }) => labels.join(' / '); const defaultDisplayRender = ({ labels }) => labels.join(' / ');
const Cascader = { const Cascader = defineComponent({
inheritAttrs: false, inheritAttrs: false,
name: 'ACascader', name: 'ACascader',
mixins: [BaseMixin], mixins: [BaseMixin],
@ -216,11 +215,13 @@ const Cascader = {
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
localeData: inject('localeData', {}), localeData: inject('localeData', {} as any),
cachedOptions: [],
popupRef: undefined,
input: undefined,
}; };
}, },
data() { data() {
this.cachedOptions = [];
const { value, defaultValue, popupVisible, showSearch, options } = this.$props; const { value, defaultValue, popupVisible, showSearch, options } = this.$props;
return { return {
sValue: value || defaultValue || [], sValue: value || defaultValue || [],
@ -246,15 +247,15 @@ const Cascader = {
}, },
options(val) { options(val) {
if (this.showSearch) { if (this.showSearch) {
this.setState({ flattenOptions: flattenTree(val, this.$props) }); this.setState({ flattenOptions: flattenTree(val, this.$props as any) });
} }
}, },
}, },
methods: { methods: {
savePopupRef(ref) { savePopupRef(ref: any) {
this.popupRef = ref; this.popupRef = ref;
}, },
highlightKeyword(str, keyword, prefixCls) { highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
return str return str
.split(keyword) .split(keyword)
.map((node, index) => .map((node, index) =>
@ -264,7 +265,13 @@ const Cascader = {
); );
}, },
defaultRenderFilteredOption({ inputValue, path, prefixCls, names }) { defaultRenderFilteredOption(opt: {
inputValue: string,
path: CascaderOptionType[],
prefixCls: string | undefined,
names: FilledFieldNamesType,
}) {
const { inputValue, path, prefixCls, names } = opt
return path.map((option, index) => { return path.map((option, index) => {
const label = option[names.label]; const label = option[names.label];
const node = const node =
@ -274,10 +281,10 @@ const Cascader = {
return index === 0 ? node : [' / ', node]; return index === 0 ? node : [' / ', node];
}); });
}, },
saveInput(node) { saveInput(node: any) {
this.input = node; this.input = node;
}, },
handleChange(value, selectedOptions) { handleChange(value: any, selectedOptions: CascaderOptionType[]) {
this.setState({ inputValue: '' }); this.setState({ inputValue: '' });
if (selectedOptions[0].__IS_FILTERED_OPTION) { if (selectedOptions[0].__IS_FILTERED_OPTION) {
const unwrappedValue = value[0]; const unwrappedValue = value[0];
@ -288,9 +295,9 @@ const Cascader = {
this.setValue(value, selectedOptions); this.setValue(value, selectedOptions);
}, },
handlePopupVisibleChange(popupVisible) { handlePopupVisibleChange(popupVisible: boolean) {
if (!hasProp(this, 'popupVisible')) { if (!hasProp(this, 'popupVisible')) {
this.setState(state => ({ this.setState((state: any) => ({
sPopupVisible: popupVisible, sPopupVisible: popupVisible,
inputFocused: popupVisible, inputFocused: popupVisible,
inputValue: popupVisible ? state.inputValue : '', inputValue: popupVisible ? state.inputValue : '',
@ -298,18 +305,18 @@ const Cascader = {
} }
this.$emit('popupVisibleChange', popupVisible); this.$emit('popupVisibleChange', popupVisible);
}, },
handleInputFocus(e) { handleInputFocus(e: InputEvent) {
this.$emit('focus', e); this.$emit('focus', e);
}, },
handleInputBlur(e) { handleInputBlur(e: InputEvent) {
this.setState({ this.setState({
inputFocused: false, inputFocused: false,
}); });
this.$emit('blur', e); this.$emit('blur', e);
}, },
handleInputClick(e) { handleInputClick(e: MouseEvent & {nativeEvent?: any}) {
const { inputFocused, sPopupVisible } = this; const { inputFocused, sPopupVisible } = this;
// Prevent `Trigger` behaviour. // Prevent `Trigger` behaviour.
if (inputFocused || sPopupVisible) { if (inputFocused || sPopupVisible) {
@ -320,19 +327,19 @@ const Cascader = {
} }
}, },
handleKeyDown(e) { handleKeyDown(e: KeyboardEvent) {
if (e.keyCode === KeyCode.BACKSPACE || e.keyCode === KeyCode.SPACE) { if (e.keyCode === KeyCode.BACKSPACE || e.keyCode === KeyCode.SPACE) {
e.stopPropagation(); e.stopPropagation();
} }
}, },
handleInputChange(e) { handleInputChange(e: Event) {
const inputValue = e.target.value; const inputValue = (e.target as any).value;
this.setState({ inputValue }); this.setState({ inputValue });
this.$emit('search', inputValue); this.$emit('search', inputValue);
}, },
setValue(value, selectedOptions) { setValue(value: string[] | number[], selectedOptions: CascaderOptionType[] = []) {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.setState({ sValue: value }); this.setState({ sValue: value });
} }
@ -355,7 +362,7 @@ const Cascader = {
return displayRender({ labels, selectedOptions }); return displayRender({ labels, selectedOptions });
}, },
clearSelection(e) { clearSelection(e: MouseEvent) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (!this.inputValue) { if (!this.inputValue) {
@ -366,23 +373,23 @@ const Cascader = {
} }
}, },
generateFilteredOptions(prefixCls, renderEmpty) { generateFilteredOptions(prefixCls: string | undefined, renderEmpty: RenderEmptyHandler) {
const { showSearch, notFoundContent } = this; const { showSearch, notFoundContent } = this;
const names = getFilledFieldNames(this.$props); const names: FilledFieldNamesType = getFilledFieldNames(this.$props);
const { const {
filter = defaultFilterOption, filter = defaultFilterOption,
// render = this.defaultRenderFilteredOption, // render = this.defaultRenderFilteredOption,
sort = defaultSortFilteredOption, sort = defaultSortFilteredOption,
limit = defaultLimit, limit = defaultLimit,
} = showSearch; } = showSearch as ShowSearchType;
const render = const render =
showSearch.render || (showSearch as ShowSearchType).render ||
getComponent(this, 'showSearchRender') || getComponent(this, 'showSearchRender') ||
this.defaultRenderFilteredOption; this.defaultRenderFilteredOption;
const { flattenOptions = [], inputValue } = this.$data; const { flattenOptions = [], inputValue } = this.$data;
// Limit the filter if needed // Limit the filter if needed
let filtered; let filtered: Array<CascaderOptionType[]>
if (limit > 0) { if (limit > 0) {
filtered = []; filtered = [];
let matchCount = 0; let matchCount = 0;
@ -453,7 +460,7 @@ const Cascader = {
showSearch = false, showSearch = false,
notFoundContent, notFoundContent,
...otherProps ...otherProps
} = props; } = props as any;
const { onEvents, extraAttrs } = splitAttrs(this.$attrs); const { onEvents, extraAttrs } = splitAttrs(this.$attrs);
const { class: className, style, ...restAttrs } = extraAttrs; const { class: className, style, ...restAttrs } = extraAttrs;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
@ -536,7 +543,7 @@ const Cascader = {
this.cachedOptions = options; this.cachedOptions = options;
} }
const dropdownMenuColumnStyle = {}; const dropdownMenuColumnStyle: CSSProperties = {};
const isNotFound = const isNotFound =
(options || []).length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND'; (options || []).length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND';
if (isNotFound) { if (isNotFound) {
@ -609,7 +616,7 @@ const Cascader = {
}; };
return <VcCascader {...cascaderProps}>{input}</VcCascader>; return <VcCascader {...cascaderProps}>{input}</VcCascader>;
}, },
}; });
Cascader.install = function(app: App) { Cascader.install = function(app: App) {
app.component(Cascader.name, Cascader); app.component(Cascader.name, Cascader);

View File

@ -1,4 +1,4 @@
import { inject } from 'vue'; import { defineComponent, inject } from 'vue';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import VcCheckbox from '../vc-checkbox'; import VcCheckbox from '../vc-checkbox';
@ -7,7 +7,7 @@ import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning'; import warning from '../_util/warning';
function noop() {} function noop() {}
export default { export default defineComponent({
name: 'ACheckbox', name: 'ACheckbox',
inheritAttrs: false, inheritAttrs: false,
__ANT_CHECKBOX: true, __ANT_CHECKBOX: true,
@ -65,17 +65,17 @@ export default {
} }
}, },
methods: { methods: {
handleChange(event) { handleChange(event: Event) {
const targetChecked = event.target.checked; const targetChecked = (event.target as any).checked;
this.$emit('update:checked', targetChecked); this.$emit('update:checked', targetChecked);
// this.$emit('input', targetChecked); // this.$emit('input', targetChecked);
this.$emit('change', event); this.$emit('change', event);
}, },
focus() { focus() {
this.$refs.vcCheckbox.focus(); (this.$refs.vcCheckbox as any).focus();
}, },
blur() { blur() {
this.$refs.vcCheckbox.blur(); (this.$refs.vcCheckbox as any).blur();
}, },
}, },
@ -93,8 +93,8 @@ export default {
class: className, class: className,
style, style,
...restAttrs ...restAttrs
} = $attrs; } = $attrs as any;
const checkboxProps = { const checkboxProps: any = {
...restProps, ...restProps,
prefixCls, prefixCls,
...restAttrs, ...restAttrs,
@ -126,12 +126,12 @@ export default {
<label <label
class={classString} class={classString}
style={style} style={style}
onMouseenter={onMouseenter} onMouseenter={onMouseenter as EventHandlerNonNull}
onMouseenter={onMouseleave} onMouseleave={onMouseleave as EventHandlerNonNull}
> >
<VcCheckbox {...checkboxProps} class={checkboxClass} ref="vcCheckbox" /> <VcCheckbox {...checkboxProps} class={checkboxClass} ref="vcCheckbox" />
{children.length ? <span>{children}</span> : null} {children.length ? <span>{children}</span> : null}
</label> </label>
); );
}, },
}; });

View File

@ -1,18 +1,27 @@
import { inject, provide } from 'vue'; import { defineComponent, inject, PropType, provide } from 'vue';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import Checkbox from './Checkbox'; import Checkbox from './Checkbox';
import hasProp, { getSlot } from '../_util/props-util'; import hasProp, { getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { VueNode } from '../_util/type';
export type CheckboxValueType = string | number | boolean;
export interface CheckboxOptionType {
label: VueNode;
value: CheckboxValueType;
disabled?: boolean;
indeterminate?: boolean;
onChange?: (e: Event) => void;
}
function noop() {} function noop() {}
export default { export default defineComponent({
name: 'ACheckboxGroup', name: 'ACheckboxGroup',
props: { props: {
name: PropTypes.string, name: PropTypes.string,
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
defaultValue: PropTypes.array, defaultValue: { type: Array as PropType<Array<CheckboxValueType>>},
value: PropTypes.array, value: { type: Array as PropType<Array<CheckboxValueType>>},
options: PropTypes.array.def([]), options: {type: Array as PropType<Array<CheckboxOptionType | string>>},
disabled: PropTypes.looseBool, disabled: PropTypes.looseBool,
onChange: PropTypes.func, onChange: PropTypes.func,
}, },
@ -54,14 +63,14 @@ export default {
return { ...option, label }; return { ...option, label };
}); });
}, },
cancelValue(value) { cancelValue(value: CheckboxValueType) {
this.registeredValues = this.registeredValues.filter(val => val !== value); this.registeredValues = this.registeredValues.filter(val => val !== value);
}, },
registerValue(value) { registerValue(value: CheckboxValueType) {
this.registeredValues = [...this.registeredValues, value]; this.registeredValues = [...this.registeredValues, value];
}, },
toggleOption(option) { toggleOption(option: CheckboxOptionType) {
const { registeredValues } = this; const { registeredValues } = this;
const optionIndex = this.sValue.indexOf(option.value); const optionIndex = this.sValue.indexOf(option.value);
const value = [...this.sValue]; const value = [...this.sValue];
@ -111,4 +120,4 @@ export default {
} }
return <div class={groupPrefixCls}>{children}</div>; return <div class={groupPrefixCls}>{children}</div>;
}, },
}; });

View File

@ -1,10 +1,11 @@
import { App } from 'vue';
import Checkbox from './Checkbox'; import Checkbox from './Checkbox';
import CheckboxGroup from './Group'; import CheckboxGroup from './Group';
Checkbox.Group = CheckboxGroup; Checkbox.Group = CheckboxGroup;
/* istanbul ignore next */ /* istanbul ignore next */
Checkbox.install = function(app) { Checkbox.install = function(app: App) {
app.component(Checkbox.name, Checkbox); app.component(Checkbox.name, Checkbox);
app.component(CheckboxGroup.name, CheckboxGroup); app.component(CheckboxGroup.name, CheckboxGroup);
return app; return app;

View File

@ -1,32 +1,53 @@
import { inject } from 'vue'; import { CSSProperties, defineComponent, inject, PropType } from 'vue';
import animation from '../_util/openAnimation'; import animation from '../_util/openAnimation';
import { import {
getOptionProps, getOptionProps,
initDefaultProps,
getComponent, getComponent,
isValidElement, isValidElement,
getSlot, getSlot,
} from '../_util/props-util'; } from '../_util/props-util';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import VcCollapse, { collapseProps } from '../vc-collapse'; import VcCollapse from '../vc-collapse';
import RightOutlined from '@ant-design/icons-vue/RightOutlined'; import RightOutlined from '@ant-design/icons-vue/RightOutlined';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import PropTypes from '../_util/vue-types';
import { tuple, VueNode } from '../_util/type';
export default { interface PanelProps {
isActive?: boolean;
header?: VueNode;
className?: string;
class?: string;
style?: CSSProperties;
showArrow?: boolean;
forceRender?: boolean;
disabled?: boolean;
extra?: VueNode;
}
type ActiveKeyType = Array<string | number> | string | number;
export default defineComponent({
name: 'ACollapse', name: 'ACollapse',
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(collapseProps(), { props: {
bordered: true, prefixCls: PropTypes.string,
openAnimation: animation, activeKey: {type: [Array, Number, String] as PropType<ActiveKeyType>},
expandIconPosition: 'left', defaultActiveKey: {type: [Array, Number, String] as PropType<ActiveKeyType>},
}), accordion: PropTypes.looseBool,
destroyInactivePanel: PropTypes.looseBool,
bordered: PropTypes.looseBool.def(true),
expandIcon: PropTypes.func,
openAnimation: PropTypes.object.def(animation),
expandIconPosition: PropTypes.oneOf(tuple('left', 'right')).def('left'),
'onUpdate:activeKey': PropTypes.func,
onChange: PropTypes.func,
},
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
}; };
}, },
methods: { methods: {
renderExpandIcon(panelProps, prefixCls) { renderExpandIcon(panelProps: PanelProps={}, prefixCls: string) {
const expandIcon = getComponent(this, 'expandIcon', panelProps); const expandIcon = getComponent(this, 'expandIcon', panelProps);
const icon = expandIcon || <RightOutlined rotate={panelProps.isActive ? 90 : undefined} />; const icon = expandIcon || <RightOutlined rotate={panelProps.isActive ? 90 : undefined} />;
return isValidElement(Array.isArray(expandIcon) ? icon[0] : icon) return isValidElement(Array.isArray(expandIcon) ? icon[0] : icon)
@ -35,7 +56,7 @@ export default {
}) })
: icon; : icon;
}, },
handleChange(activeKey) { handleChange(activeKey: ActiveKeyType) {
this.$emit('update:activeKey', activeKey); this.$emit('update:activeKey', activeKey);
this.$emit('change', activeKey); this.$emit('change', activeKey);
}, },
@ -44,7 +65,7 @@ export default {
const { prefixCls: customizePrefixCls, bordered, expandIconPosition } = this; const { prefixCls: customizePrefixCls, bordered, expandIconPosition } = this;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('collapse', customizePrefixCls); const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const { class: className, ...restAttrs } = this.$attrs; const { class: className, ...restAttrs } = this.$attrs as any;
const collapseClassName = { const collapseClassName = {
[className]: className, [className]: className,
[`${prefixCls}-borderless`]: !bordered, [`${prefixCls}-borderless`]: !bordered,
@ -53,13 +74,12 @@ export default {
const rcCollapeProps = { const rcCollapeProps = {
...getOptionProps(this), ...getOptionProps(this),
prefixCls, prefixCls,
expandIcon: panelProps => this.renderExpandIcon(panelProps, prefixCls), expandIcon: (panelProps: PanelProps) => this.renderExpandIcon(panelProps, prefixCls),
class: collapseClassName, class: collapseClassName,
...restAttrs, ...restAttrs,
onChange: this.handleChange, onChange: this.handleChange,
'onUpdate:change': undefined,
}; };
return <VcCollapse {...rcCollapeProps}>{getSlot(this)}</VcCollapse>; return <VcCollapse {...rcCollapeProps}>{getSlot(this)}</VcCollapse>;
}, },
}; });

View File

@ -1,13 +1,26 @@
import { inject } from 'vue'; import { defineComponent, inject } from 'vue';
import { getOptionProps, getComponent, getSlot } from '../_util/props-util'; import { getOptionProps, getComponent, getSlot } from '../_util/props-util';
import VcCollapse, { panelProps } from '../vc-collapse'; import VcCollapse from '../vc-collapse';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import PropTypes from '../_util/vue-types';
export default { export default defineComponent({
name: 'ACollapsePanel', name: 'ACollapsePanel',
inheritAttrs: false, inheritAttrs: false,
props: { props: {
...panelProps(), openAnimation: PropTypes.object,
prefixCls: PropTypes.string,
header: PropTypes.VNodeChild,
headerClass: PropTypes.string,
showArrow: PropTypes.looseBool,
isActive: PropTypes.looseBool,
destroyInactivePanel: PropTypes.looseBool,
disabled: PropTypes.looseBool,
accordion: PropTypes.looseBool,
forceRender: PropTypes.looseBool,
expandIcon: PropTypes.func,
extra: PropTypes.VNodeChild,
panelKey: PropTypes.VNodeChild,
}, },
setup() { setup() {
return { return {
@ -18,7 +31,7 @@ export default {
const { prefixCls: customizePrefixCls, showArrow = true } = this; const { prefixCls: customizePrefixCls, showArrow = true } = this;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('collapse', customizePrefixCls); const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const { class: className, ...restAttrs } = this.$attrs; const { class: className, ...restAttrs } = this.$attrs as any;
const collapsePanelClassName = { const collapsePanelClassName = {
[className]: className, [className]: className,
[`${prefixCls}-no-arrow`]: !showArrow, [`${prefixCls}-no-arrow`]: !showArrow,
@ -34,4 +47,4 @@ export default {
}; };
return <VcCollapse.Panel {...rcCollapePanelProps}>{getSlot(this)}</VcCollapse.Panel>; return <VcCollapse.Panel {...rcCollapePanelProps}>{getSlot(this)}</VcCollapse.Panel>;
}, },
}; });

View File

@ -1,94 +1,101 @@
import { inject, VNodeTypes, CSSProperties, App, SetupContext } from 'vue'; import { App, defineComponent, inject } from 'vue';
import classNames from '../_util/classNames'; import PropsTypes from '../_util/vue-types';
import { getComponent, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { VueNode } from '../_util/type';
export interface CommentProps { export const CommentProps = {
/** List of action items rendered below the comment content */ actions: PropsTypes.array,
actions?: Array<VNodeTypes>;
/** The element to display as the comment author. */ /** The element to display as the comment author. */
author?: VNodeTypes; author: PropsTypes.VNodeChild,
/** The element to display as the comment avatar - generally an antd Avatar */ /** The element to display as the comment avatar - generally an antd Avatar */
avatar?: VNodeTypes; avatar: PropsTypes.VNodeChild,
/** The main content of the comment */ /** The main content of the comment */
content: VNodeTypes; content: PropsTypes.VNodeChild,
/** Comment prefix defaults to '.ant-comment' */ /** Comment prefix defaults to '.ant-comment' */
prefixCls?: string; prefixCls: PropsTypes.string,
/** Additional style for the comment */
style?: CSSProperties;
/** A datetime element containing the time to be displayed */ /** A datetime element containing the time to be displayed */
datetime?: VNodeTypes; datetime: PropsTypes.VNodeChild,
} };
const Comment = ( const Comment = defineComponent({
{ name: 'AComment',
actions, props: CommentProps,
author, setup() {
avatar, return {
content, configProvider: inject('configProvider', defaultConfigProvider),
prefixCls: customizePrefixCls, };
datetime, },
...otherProps methods: {
}: CommentProps, getAction(actions: VueNode[]) {
{ slots }: SetupContext, if (!actions || !actions.length) {
) => { return null;
const { getPrefixCls } = inject('configProvider', defaultConfigProvider); }
const actionList = actions.map((action, index) => <li key={`action-${index}`}>{action}</li>);
return actionList;
},
renderNested(prefixCls: string, children: VueNode) {
return <div class={`${prefixCls}-nested`}>{children}</div>;
},
},
const renderNested = (prefixCls: string, nestedChildren: any) => { render() {
return <div class={classNames(`${prefixCls}-nested`)}>{nestedChildren}</div>; const { prefixCls: customizePrefixCls } = this.$props;
};
const prefixCls = getPrefixCls('comment', customizePrefixCls); const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('comment', customizePrefixCls);
const avatarDom = avatar ? ( const actions = getComponent(this, 'actions');
<div class={`${prefixCls}-avatar`}> const author = getComponent(this, 'author');
{typeof avatar === 'string' ? <img src={avatar} alt="comment-avatar" /> : avatar} const avatar = getComponent(this, 'avatar');
</div> const content = getComponent(this, 'content');
) : null; const datetime = getComponent(this, 'datetime');
const actionDom = const avatarDom = (
actions && actions.length ? ( <div class={`${prefixCls}-avatar`}>
{typeof avatar === 'string' ? <img src={avatar} alt="comment-avatar" /> : avatar}
</div>
);
const actionDom = actions ? (
<ul class={`${prefixCls}-actions`}> <ul class={`${prefixCls}-actions`}>
{actions.map((action, index) => ( {this.getAction(Array.isArray(actions) ? actions : [actions])}
<li key={`action-${index}`}>{action}</li>
))}
</ul> </ul>
) : null; ) : null;
const authorContent = (author || datetime) && ( const authorContent = (
<div class={`${prefixCls}-content-author`}> <div class={`${prefixCls}-content-author`}>
{author && <span class={`${prefixCls}-content-author-name`}>{author}</span>} {author && <span class={`${prefixCls}-content-author-name`}>{author}</span>}
{datetime && <span class={`${prefixCls}-content-author-time`}>{datetime}</span>} {datetime && <span class={`${prefixCls}-content-author-time`}>{datetime}</span>}
</div> </div>
); );
const contentDom = ( const contentDom = (
<div class={`${prefixCls}-content`}> <div class={`${prefixCls}-content`}>
{authorContent} {authorContent}
<div class={`${prefixCls}-content-detail`}>{content}</div> <div class={`${prefixCls}-content-detail`}>{content}</div>
{actionDom} {actionDom}
</div> </div>
); );
const cls = classNames(prefixCls);
const children = slots.default?.(); const comment = (
return (
<div {...otherProps} class={cls}>
<div class={`${prefixCls}-inner`}> <div class={`${prefixCls}-inner`}>
{avatarDom} {avatarDom}
{contentDom} {contentDom}
</div> </div>
{children ? renderNested(prefixCls, children) : null} );
</div> const children = getSlot(this);
); return (
}; <div class={prefixCls}>
{comment}
Comment.displayName = 'AComment'; {children && children.length ? this.renderNested(prefixCls, children) : null}
</div>
);
},
});
/* istanbul ignore next */ /* istanbul ignore next */
Comment.install = function(app: App) { Comment.install = function(app: App) {
app.component(Comment.name, Comment); app.component(Comment.name, Comment);
return app; return app;
}; };
export default Comment; export default Comment;

View File

@ -1,13 +1,22 @@
import { SetupContext, VNode } from 'vue';
import { getOptionProps } from '../_util/props-util'; import { getOptionProps } from '../_util/props-util';
const Col = (_, { attrs }) => { interface ColProps {
const { child = {}, bordered, colon, type, layout, colKey: key } = attrs; child: VNode;
bordered: boolean;
colon: boolean;
type?: 'label' | 'content';
layout?: 'horizontal' | 'vertical';
colKey?: string
}
const Col = (_props: ColProps, { attrs }: SetupContext) => {
const { child = {} as VNode, bordered, colon, type, layout, colKey: key } = attrs as unknown as ColProps;
const { prefixCls, span = 1 } = getOptionProps(child); const { prefixCls, span = 1 } = getOptionProps(child);
const { children = {}, props = {} } = child; const { children = {} as any, props = {} } = child;
const label = props.label || (children.label && children.label()); const label = props.label || (children.label && children.label());
const defaultSlot = children.default && children.default(); const defaultSlot = children.default && children.default();
const labelProps = { const labelProps: any = {
class: [ class: [
`${prefixCls}-item-label`, `${prefixCls}-item-label`,
{ {

View File

@ -1,17 +1,17 @@
import { inject, cloneVNode } from 'vue'; import { inject, cloneVNode, App, defineComponent, PropType, VNode } from 'vue';
import warning from '../_util/warning'; import warning from '../_util/warning';
import ResponsiveObserve, { responsiveArray } from '../_util/responsiveObserve'; import ResponsiveObserve, { Breakpoint, responsiveArray } from '../_util/responsiveObserve';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import Col from './Col'; import Col from './Col';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { import {
initDefaultProps,
getOptionProps, getOptionProps,
getComponent, getComponent,
isValidElement, isValidElement,
getSlot, getSlot,
} from '../_util/props-util'; } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { tuple, VueNode } from '../_util/type';
export const DescriptionsItemProps = { export const DescriptionsItemProps = {
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
@ -19,7 +19,7 @@ export const DescriptionsItemProps = {
span: PropTypes.number, span: PropTypes.number,
}; };
function toArray(value) { function toArray(value: any) {
let ret = value; let ret = value;
if (value === undefined) { if (value === undefined) {
ret = []; ret = [];
@ -31,19 +31,35 @@ function toArray(value) {
export const DescriptionsItem = { export const DescriptionsItem = {
name: 'ADescriptionsItem', name: 'ADescriptionsItem',
props: initDefaultProps(DescriptionsItemProps, { span: 1 }), props: {
prefixCls: PropTypes.string,
label: PropTypes.VNodeChild,
span: PropTypes.number.def(1),
},
render() { render() {
return null; return null;
}, },
}; };
const defaultColumnMap = {
xxl: 3,
xl: 3,
lg: 3,
md: 3,
sm: 2,
xs: 1,
};
export const DescriptionsProps = { export const DescriptionsProps = {
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
bordered: PropTypes.looseBool, bordered: PropTypes.looseBool,
size: PropTypes.oneOf(['default', 'middle', 'small']).def('default'), size: PropTypes.oneOf(tuple('default', 'middle', 'small')).def('default'),
title: PropTypes.any, title: PropTypes.VNodeChild,
column: PropTypes.oneOfType([PropTypes.number, PropTypes.object]), column: {
layout: PropTypes.oneOf(['horizontal', 'vertical']), type: [Number, Object] as PropType<number | Partial<Record<Breakpoint, number>>>,
default: () => defaultColumnMap
},
layout: PropTypes.oneOf(tuple('horizontal', 'vertical')),
colon: PropTypes.looseBool, colon: PropTypes.looseBool,
}; };
@ -52,13 +68,13 @@ export const DescriptionsProps = {
* @param children: DescriptionsItem * @param children: DescriptionsItem
* @param column: number * @param column: number
*/ */
const generateChildrenRows = (children, column) => { const generateChildrenRows = (children: VueNode, column: number) => {
const rows = []; const rows = [];
let columns = null; let columns = null;
let leftSpans; let leftSpans: number;
const itemNodes = toArray(children); const itemNodes = toArray(children);
itemNodes.forEach((node, index) => { itemNodes.forEach((node: VNode, index: number) => {
const itemProps = getOptionProps(node); const itemProps = getOptionProps(node);
let itemNode = node; let itemNode = node;
@ -97,22 +113,11 @@ const generateChildrenRows = (children, column) => {
return rows; return rows;
}; };
const defaultColumnMap = { const Descriptions = defineComponent({
xxl: 3,
xl: 3,
lg: 3,
md: 3,
sm: 2,
xs: 1,
};
const Descriptions = {
name: 'ADescriptions', name: 'ADescriptions',
Item: DescriptionsItem, Item: DescriptionsItem,
mixins: [BaseMixin], mixins: [BaseMixin],
props: initDefaultProps(DescriptionsProps, { props: DescriptionsProps,
column: defaultColumnMap,
}),
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
@ -143,8 +148,19 @@ const Descriptions = {
// Maybe there are some strange environments // Maybe there are some strange environments
return 3; return 3;
}, },
renderRow(children, index, { prefixCls }, bordered, layout, colon) { renderRow(
const renderCol = (colItem, type, idx) => { children: VNode[],
index: number,
{ prefixCls }: { prefixCls: string },
bordered: boolean,
layout: 'horizontal' | 'vertical',
colon: boolean
) {
const renderCol = (
colItem: VNode,
type: 'label' | 'content',
idx: number
) => {
return ( return (
<Col <Col
child={colItem} child={colItem}
@ -160,7 +176,7 @@ const Descriptions = {
const cloneChildren = []; const cloneChildren = [];
const cloneContentChildren = []; const cloneContentChildren = [];
toArray(children).forEach((childrenItem, idx) => { toArray(children).forEach((childrenItem: VNode, idx: number) => {
cloneChildren.push(renderCol(childrenItem, 'label', idx)); cloneChildren.push(renderCol(childrenItem, 'label', idx));
if (layout === 'vertical') { if (layout === 'vertical') {
cloneContentChildren.push(renderCol(childrenItem, 'content', idx)); cloneContentChildren.push(renderCol(childrenItem, 'content', idx));
@ -216,7 +232,7 @@ const Descriptions = {
const column = this.getColumn(); const column = this.getColumn();
const children = getSlot(this); const children = getSlot(this);
const cloneChildren = toArray(children) const cloneChildren = toArray(children)
.map(child => { .map((child: VNode) => {
if (isValidElement(child)) { if (isValidElement(child)) {
return cloneVNode(child, { return cloneVNode(child, {
prefixCls, prefixCls,
@ -259,9 +275,9 @@ const Descriptions = {
</div> </div>
); );
}, },
}; });
Descriptions.install = function(app) { Descriptions.install = function(app: App) {
app.component(Descriptions.name, Descriptions); app.component(Descriptions.name, Descriptions);
app.component(Descriptions.Item.name, Descriptions.Item); app.component(Descriptions.Item.name, Descriptions.Item);
return app; return app;

View File

@ -1,4 +1,4 @@
import { App, computed, defineComponent, inject, PropType, unref } from 'vue'; import { App, computed, defineComponent, inject, PropType } from 'vue';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
const Divider = defineComponent({ const Divider = defineComponent({
@ -25,7 +25,7 @@ const Divider = defineComponent({
const classString = computed(() => { const classString = computed(() => {
const { type, dashed, orientation } = props; const { type, dashed, orientation } = props;
const orientationPrefix = orientation.length > 0 ? '-' + orientation : orientation; const orientationPrefix = orientation.length > 0 ? '-' + orientation : orientation;
const prefixClsRef = unref(prefixCls); const prefixClsRef = prefixCls.value;
return { return {
[prefixClsRef]: true, [prefixClsRef]: true,
[`${prefixClsRef}-${type}`]: true, [`${prefixClsRef}-${type}`]: true,

View File

@ -18,7 +18,6 @@ const collapseProps = () => ({
expandIcon: PropTypes.func, expandIcon: PropTypes.func,
openAnimation: PropTypes.object, openAnimation: PropTypes.object,
expandIconPosition: PropTypes.oneOf(['left', 'right']), expandIconPosition: PropTypes.oneOf(['left', 'right']),
'onUpdate:change': PropTypes.func,
onChange: PropTypes.func, onChange: PropTypes.func,
}); });