chore: refactor space

pull/2926/head
Amour1688 2020-08-16 00:21:58 +08:00
parent 07d27b057a
commit 4af81c412c
24 changed files with 513 additions and 453 deletions

View File

@ -1,6 +1,6 @@
import isPlainObject from 'lodash/isPlainObject';
import classNames from 'classnames';
import { isVNode, Fragment, Comment, Text, h } from 'vue';
import { isVNode, Fragment, Comment, Text, h, VNode, Prop, PropOptions } from 'vue';
import { camelize, hyphenate, isOn, resolvePropValue } from './util';
import isValid from './isValid';
// function getType(fn) {
@ -345,8 +345,8 @@ export function isStringElement(c) {
return c && c.type === Text;
}
export function filterEmpty(children = []) {
const res = [];
export function filterEmpty(children: VNode[] = []) {
const res: VNode[] = [];
children.forEach(child => {
if (Array.isArray(child)) {
res.push(...child);
@ -358,10 +358,14 @@ export function filterEmpty(children = []) {
});
return res.filter(c => !isEmptyElement(c));
}
const initDefaultProps = (propTypes, defaultProps) => {
Object.keys(defaultProps).forEach(k => {
if (propTypes[k]) {
propTypes[k].def && (propTypes[k] = propTypes[k].def(defaultProps[k]));
const initDefaultProps = <T>(
propTypes: T,
defaultProps: { [K in Extract<keyof T, string>]?: any },
): T => {
Object.keys(defaultProps).forEach((k: Extract<keyof T, string>) => {
let prop = propTypes[k] as PropOptions<any>;
if (prop) {
prop.default = defaultProps[k];
} else {
throw new Error(`not have ${k} prop`);
}

View File

@ -1,26 +1,10 @@
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
let enquire;
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
// TODO: Will be removed in antd 4.0 because we will no longer support ie9
if (typeof window !== 'undefined') {
const matchMediaPolyfill = mediaQuery => {
return {
media: mediaQuery,
matches: false,
addListener() {},
removeListener() {},
};
};
// ref: https://github.com/ant-design/ant-design/issues/18774
if (!window.matchMedia) window.matchMedia = matchMediaPolyfill;
// eslint-disable-next-line global-require
enquire = require('enquire.js');
}
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
export const responsiveArray = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
export const responsiveMap = {
export const responsiveMap: BreakpointMap = {
xs: '(max-width: 575px)',
sm: '(min-width: 576px)',
md: '(min-width: 768px)',
@ -29,65 +13,60 @@ export const responsiveMap = {
xxl: '(min-width: 1600px)',
};
let subscribers = [];
type SubscribeFunc = (screens: ScreenMap) => void;
const subscribers = new Map<Number, SubscribeFunc>();
let subUid = -1;
let screens = {};
const responsiveObserve = {
dispatch(pointMap) {
matchHandlers: {} as {
[prop: string]: {
mql: MediaQueryList;
listener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null;
};
},
dispatch(pointMap: ScreenMap) {
screens = pointMap;
if (subscribers.length < 1) {
return false;
}
subscribers.forEach(item => {
item.func(screens);
});
return true;
subscribers.forEach(func => func(screens));
return subscribers.size >= 1;
},
subscribe(func) {
if (subscribers.length === 0) {
this.register();
}
const token = (++subUid).toString();
subscribers.push({
token,
func,
});
subscribe(func: SubscribeFunc): number {
if (!subscribers.size) this.register();
subUid += 1;
subscribers.set(subUid, func);
func(screens);
return token;
return subUid;
},
unsubscribe(token) {
subscribers = subscribers.filter(item => item.token !== token);
if (subscribers.length === 0) {
this.unregister();
}
unsubscribe(token: number) {
subscribers.delete(token);
if (!subscribers.size) this.unregister();
},
unregister() {
Object.keys(responsiveMap).map(screen => enquire.unregister(responsiveMap[screen]));
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen]!;
const handler = this.matchHandlers[matchMediaQuery];
handler?.mql.removeListener(handler?.listener);
});
subscribers.clear();
},
register() {
Object.keys(responsiveMap).map(screen =>
enquire.register(responsiveMap[screen], {
match: () => {
const pointMap = {
...screens,
[screen]: true,
};
this.dispatch(pointMap);
},
unmatch: () => {
const pointMap = {
...screens,
[screen]: false,
};
this.dispatch(pointMap);
},
// Keep a empty destroy to avoid triggering unmatch when unregister
destroy() {},
}),
);
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen]!;
const listener = ({ matches }: { matches: boolean }) => {
this.dispatch({
...screens,
[screen]: matches,
});
};
const mql = window.matchMedia(matchMediaQuery);
mql.addListener(listener);
this.matchHandlers[matchMediaQuery] = {
mql,
listener,
};
listener(mql);
});
},
};

View File

@ -1,4 +1,4 @@
// https://stackoverflow.com/questions/46176165/ways-to-get-string-literal-type-of-array-values-without-enum-overhead
export const tuple = (...args) => args;
export const tuple = <T extends string[]>(...args: T) => args;
export const tupleNum = (...args) => args;

View File

@ -1,3 +1,4 @@
import { PropType } from 'vue';
import isPlainObject from 'lodash/isPlainObject';
import { toType, getType, isFunction, validateType, isInteger, isArray, warn } from './utils';
@ -9,57 +10,57 @@ const VuePropTypes = {
},
get func() {
return toType('function', {
return {
type: Function,
}).def(currentDefaults.func);
};
},
get bool() {
return toType('boolean', {
return {
type: Boolean,
}).def(currentDefaults.bool);
};
},
get string() {
return toType('string', {
return {
type: String,
}).def(currentDefaults.string);
};
},
get number() {
return toType('number', {
return {
type: Number,
}).def(currentDefaults.number);
};
},
get array() {
return toType('array', {
return {
type: Array,
}).def(currentDefaults.array);
};
},
get object() {
return toType('object', {
return {
type: Object,
}).def(currentDefaults.object);
};
},
get integer() {
return toType('integer', {
return {
type: Number,
validator(value) {
validator(value: number) {
return isInteger(value);
},
}).def(currentDefaults.integer);
};
},
get symbol() {
return toType('symbol', {
return {
type: null,
validator(value) {
validator(value: Symbol) {
return typeof value === 'symbol';
},
});
};
},
custom(validatorFn, warnMsg = 'custom validation failed') {
@ -76,7 +77,13 @@ const VuePropTypes = {
});
},
oneOf(arr) {
tuple<T>() {
return {
type: (String as unknown) as PropType<T>,
};
},
oneOf(arr: unknown[]) {
if (!isArray(arr)) {
throw new TypeError('[VueTypes error]: You must provide an array as argument');
}
@ -90,7 +97,7 @@ const VuePropTypes = {
return toType('oneOf', {
type: allowedTypes.length > 0 ? allowedTypes : null,
validator(value) {
validator(value: unknown) {
const valid = arr.indexOf(value) !== -1;
if (!valid) warn(msg);
return valid;
@ -98,10 +105,10 @@ const VuePropTypes = {
});
},
instanceOf(instanceConstructor) {
return toType('instanceOf', {
instanceOf<T>(instanceConstructor: T) {
return {
type: instanceConstructor,
});
};
},
oneOfType(arr) {
@ -158,10 +165,10 @@ const VuePropTypes = {
}).def(undefined);
},
arrayOf(type) {
arrayOf<T extends object>(type: T) {
return toType('arrayOf', {
type: Array,
validator(values) {
type: Array as PropType<T[]>,
validator(values: T[]) {
const valid = values.every(value => validateType(type, value));
if (!valid) warn(`arrayOf - value must be an array of "${getType(type)}"`);
return valid;
@ -171,8 +178,8 @@ const VuePropTypes = {
objectOf(type) {
return toType('objectOf', {
type: Object,
validator(obj) {
type: Object as PropType<T>,
validator(obj: T): obj is T {
const valid = Object.keys(obj).every(key => validateType(type, obj[key]));
if (!valid) warn(`objectOf - value must be an object of "${getType(type)}"`);
return valid;

View File

@ -1,6 +1,7 @@
import { App } from 'vue';
import { Col } from '../grid';
/* istanbul ignore next */
Col.install = function(app) {
Col.install = function(app: App) {
app.component(Col.name, Col);
};

View File

@ -1,9 +1,10 @@
import { defineComponent, CSSProperties, VNodeChild, inject, App } from 'vue';
import { defineComponent, CSSProperties, VNodeChild, inject, App, PropType, VNode } from 'vue';
import classNames from 'classnames';
import { ConfigConsumerProps } from '../config-provider';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import DefaultEmptyImg from './empty';
import SimpleEmptyImg from './simple';
import { filterEmpty } from '../_util/props-util';
const defaultEmptyImg = <DefaultEmptyImg />;
const simpleEmptyImg = <SimpleEmptyImg />;
@ -12,19 +13,23 @@ export interface TransferLocale {
description: string;
}
export interface EmptyProps {
prefixCls?: string;
class?: string;
style?: CSSProperties;
imageStyle?: CSSProperties;
image?: VNodeChild;
description?: VNodeChild;
children?: VNodeChild;
}
const Empty = defineComponent<EmptyProps>({
const Empty = defineComponent({
name: 'AEmpty',
setup(props) {
props: {
prefixCls: {
type: String,
},
imageStyle: {
type: Object as PropType<string | CSSProperties>,
},
image: {
type: Object as PropType<VNode>,
},
description: {
type: String,
},
},
setup(props, { slots }) {
const configProvider = inject('configProvider', ConfigConsumerProps);
const { getPrefixCls } = configProvider;
const {
@ -32,7 +37,6 @@ const Empty = defineComponent<EmptyProps>({
prefixCls: customizePrefixCls,
image = defaultEmptyImg,
description,
children,
imageStyle,
...restProps
} = props;
@ -44,7 +48,6 @@ const Empty = defineComponent<EmptyProps>({
const prefixCls = getPrefixCls('empty', customizePrefixCls);
const des = typeof description !== 'undefined' ? description : locale.description;
const alt = typeof des === 'string' ? des : 'empty';
let imageNode: any = null;
if (typeof image === 'string') {
@ -68,7 +71,9 @@ const Empty = defineComponent<EmptyProps>({
{imageNode}
</div>
{des && <p class={`${prefixCls}-description`}>{des}</p>}
{children && <div class={`${prefixCls}-footer`}>{children}</div>}
{slots.default && (
<div class={`${prefixCls}-footer`}>{filterEmpty(slots.default?.())}</div>
)}
</div>
) as VNodeChild;
}}

View File

@ -1,125 +0,0 @@
import { inject } from 'vue';
import PropTypes from '../_util/vue-types';
import { ConfigConsumerProps } from '../config-provider';
import { getSlot } from '../_util/props-util';
const stringOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
export const ColSize = PropTypes.shape({
span: stringOrNumber,
order: stringOrNumber,
offset: stringOrNumber,
push: stringOrNumber,
pull: stringOrNumber,
}).loose;
const objectOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number, ColSize]);
export const ColProps = {
span: stringOrNumber,
order: stringOrNumber,
offset: stringOrNumber,
push: stringOrNumber,
pull: stringOrNumber,
xs: objectOrNumber,
sm: objectOrNumber,
md: objectOrNumber,
lg: objectOrNumber,
xl: objectOrNumber,
xxl: objectOrNumber,
prefixCls: PropTypes.string,
flex: stringOrNumber,
};
export default {
name: 'ACol',
props: ColProps,
setup() {
return {
configProvider: inject('configProvider', ConfigConsumerProps),
rowContext: inject('rowContext', null),
};
},
methods: {
parseFlex(flex) {
if (typeof flex === 'number') {
return `${flex} ${flex} auto`;
}
if (/^\d+(\.\d+)?(px|em|rem|%)$/.test(flex)) {
return `0 0 ${flex}`;
}
return flex;
},
},
render() {
const {
span,
order,
offset,
push,
pull,
flex,
prefixCls: customizePrefixCls,
rowContext,
} = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('col', customizePrefixCls);
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
let sizeProps = {};
const propSize = this[size];
if (typeof propSize === 'number') {
sizeProps.span = propSize;
} else if (typeof propSize === 'object') {
sizeProps = propSize || {};
}
sizeClassObj = {
...sizeClassObj,
[`${prefixCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
[`${prefixCls}-${size}-order-${sizeProps.order}`]: sizeProps.order || sizeProps.order === 0,
[`${prefixCls}-${size}-offset-${sizeProps.offset}`]:
sizeProps.offset || sizeProps.offset === 0,
[`${prefixCls}-${size}-push-${sizeProps.push}`]: sizeProps.push || sizeProps.push === 0,
[`${prefixCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull || sizeProps.pull === 0,
};
});
const classes = {
[`${prefixCls}`]: true,
[`${prefixCls}-${span}`]: span !== undefined,
[`${prefixCls}-order-${order}`]: order,
[`${prefixCls}-offset-${offset}`]: offset,
[`${prefixCls}-push-${push}`]: push,
[`${prefixCls}-pull-${pull}`]: pull,
...sizeClassObj,
};
const divProps = {
class: classes,
style: {},
};
if (rowContext) {
const gutter = rowContext.getGutter();
if (gutter) {
divProps.style = {
...(gutter[0] > 0
? {
paddingLeft: `${gutter[0] / 2}px`,
paddingRight: `${gutter[0] / 2}px`,
}
: {}),
...(gutter[1] > 0
? {
paddingTop: `${gutter[1] / 2}px`,
paddingBottom: `${gutter[1] / 2}px`,
}
: {}),
};
}
}
if (flex) {
divProps.style.flex = this.parseFlex(flex);
}
return <div {...divProps}>{getSlot(this)}</div>;
},
};

131
components/grid/Col.tsx Normal file
View File

@ -0,0 +1,131 @@
import { inject, defineComponent, HTMLAttributes, CSSProperties } from 'vue';
import classNames from 'classnames';
import { ConfigConsumerProps } from '../config-provider';
import { rowContextState } from './Row';
type ColSpanType = number | string;
type FlexType = number | 'none' | 'auto' | string;
export interface ColSize {
span?: ColSpanType;
order?: ColSpanType;
offset?: ColSpanType;
push?: ColSpanType;
pull?: ColSpanType;
}
export interface ColProps extends HTMLAttributes {
span?: ColSpanType;
order?: ColSpanType;
offset?: ColSpanType;
push?: ColSpanType;
pull?: ColSpanType;
xs?: ColSpanType | ColSize;
sm?: ColSpanType | ColSize;
md?: ColSpanType | ColSize;
lg?: ColSpanType | ColSize;
xl?: ColSpanType | ColSize;
xxl?: ColSpanType | ColSize;
prefixCls?: string;
flex?: FlexType;
}
function parseFlex(flex: FlexType): string {
if (typeof flex === 'number') {
return `${flex} ${flex} auto`;
}
if (/^\d+(\.\d+)?(px|em|rem|%)$/.test(flex)) {
return `0 0 ${flex}`;
}
return flex;
}
export default defineComponent<ColProps>({
name: 'ACol',
setup(props, { slots }) {
const configProvider = inject('configProvider', ConfigConsumerProps);
const rowContext = inject<rowContextState>('rowContext', {});
return () => {
const { gutter } = rowContext;
const {
prefixCls: customizePrefixCls,
span,
order,
offset,
push,
pull,
class: className,
flex,
style,
...others
} = props;
const prefixCls = configProvider.getPrefixCls('col', customizePrefixCls);
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
let sizeProps: ColSize = {};
const propSize = (props as any)[size];
if (typeof propSize === 'number') {
sizeProps.span = propSize;
} else if (typeof propSize === 'object') {
sizeProps = propSize || {};
}
delete (others as any)[size];
sizeClassObj = {
...sizeClassObj,
[`${prefixCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
[`${prefixCls}-${size}-order-${sizeProps.order}`]:
sizeProps.order || sizeProps.order === 0,
[`${prefixCls}-${size}-offset-${sizeProps.offset}`]:
sizeProps.offset || sizeProps.offset === 0,
[`${prefixCls}-${size}-push-${sizeProps.push}`]: sizeProps.push || sizeProps.push === 0,
[`${prefixCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull || sizeProps.pull === 0,
};
});
const classes = classNames(
prefixCls,
{
[`${prefixCls}-${span}`]: span !== undefined,
[`${prefixCls}-order-${order}`]: order,
[`${prefixCls}-offset-${offset}`]: offset,
[`${prefixCls}-push-${push}`]: push,
[`${prefixCls}-pull-${pull}`]: pull,
},
className,
sizeClassObj,
);
let mergedStyle: CSSProperties = {};
if (gutter) {
mergedStyle = {
...(gutter[0]! > 0
? {
paddingLeft: gutter[0]! / 2,
paddingRight: gutter[0]! / 2,
}
: {}),
...(gutter[1]! > 0
? {
paddingTop: gutter[1]! / 2,
paddingBottom: gutter[1]! / 2,
}
: {}),
...mergedStyle,
};
}
if (flex) {
mergedStyle.flex = parseFlex(flex);
}
return (
<div {...others} style={mergedStyle} class={classes}>
{slots.default?.()}
</div>
);
};
},
});

View File

@ -1,114 +0,0 @@
import { inject, provide, reactive } from 'vue';
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
import { ConfigConsumerProps } from '../config-provider';
import ResponsiveObserve from '../_util/responsiveObserve';
import { getSlot } from '../_util/props-util';
const RowProps = {
gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
type: PropTypes.oneOf(['flex']),
align: PropTypes.oneOf(['top', 'middle', 'bottom', 'stretch']),
justify: PropTypes.oneOf(['start', 'end', 'center', 'space-around', 'space-between']),
prefixCls: PropTypes.string,
};
const responsiveArray = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
export default {
name: 'ARow',
mixins: [BaseMixin],
props: {
...RowProps,
gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]).def(0),
},
setup() {
const rowContext = reactive({
getGutter: undefined,
});
provide('rowContext', rowContext);
return {
configProvider: inject('configProvider', ConfigConsumerProps),
rowContext,
};
},
data() {
return {
screens: {},
};
},
created() {
this.rowContext.getGutter = this.getGutter;
},
mounted() {
this.$nextTick(() => {
this.token = ResponsiveObserve.subscribe(screens => {
const { gutter } = this;
if (
typeof gutter === 'object' ||
(Array.isArray(gutter) &&
(typeof gutter[0] === 'object' || typeof gutter[1] === 'object'))
) {
this.screens = screens;
}
});
});
},
beforeUnmount() {
ResponsiveObserve.unsubscribe(this.token);
},
methods: {
getGutter() {
const results = [0, 0];
const { gutter, screens } = this;
const normalizedGutter = Array.isArray(gutter) ? gutter : [gutter, 0];
normalizedGutter.forEach((g, index) => {
if (typeof g === 'object') {
for (let i = 0; i < responsiveArray.length; i++) {
const breakpoint = responsiveArray[i];
if (screens[breakpoint] && g[breakpoint] !== undefined) {
results[index] = g[breakpoint];
break;
}
}
} else {
results[index] = g || 0;
}
});
return results;
},
},
render() {
const { type, justify, align, prefixCls: customizePrefixCls } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('row', customizePrefixCls);
const gutter = this.getGutter();
const classes = {
[prefixCls]: !type,
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${type}-${justify}`]: type && justify,
[`${prefixCls}-${type}-${align}`]: type && align,
};
const rowStyle = {
...(gutter[0] > 0
? {
marginLeft: `${gutter[0] / -2}px`,
marginRight: `${gutter[0] / -2}px`,
}
: {}),
...(gutter[1] > 0
? {
marginTop: `${gutter[1] / -2}px`,
marginBottom: `${gutter[1] / -2}px`,
}
: {}),
};
return (
<div class={classes} style={rowStyle}>
{getSlot(this)}
</div>
);
},
};

149
components/grid/Row.tsx Normal file
View File

@ -0,0 +1,149 @@
import {
inject,
provide,
reactive,
defineComponent,
HTMLAttributes,
ref,
onMounted,
onBeforeUnmount,
} from 'vue';
import classNames from 'classnames';
import { tuple } from '../_util/type';
import PropTypes from '../_util/vue-types';
import { ConfigConsumerProps } from '../config-provider';
import ResponsiveObserve, {
Breakpoint,
ScreenMap,
responsiveArray,
} from '../_util/responsiveObserve';
const RowProps = {
gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
type: PropTypes.oneOf(['flex']),
align: PropTypes.oneOf(['top', 'middle', 'bottom', 'stretch']),
justify: PropTypes.oneOf(['start', 'end', 'center', 'space-around', 'space-between']),
prefixCls: PropTypes.string,
};
const RowAligns = tuple('top', 'middle', 'bottom', 'stretch');
const RowJustify = tuple('start', 'end', 'center', 'space-around', 'space-between');
export type Gutter = number | Partial<Record<Breakpoint, number>>;
export interface rowContextState {
gutter?: [number, number];
}
export interface RowProps extends HTMLAttributes {
gutter?: Gutter | [Gutter, Gutter];
align?: typeof RowAligns[number];
justify?: typeof RowJustify[number];
prefixCls?: string;
}
export default defineComponent<RowProps>({
name: 'ARow',
setup(props, { slots }) {
const rowContext = reactive<rowContextState>({
gutter: undefined,
});
provide('rowContext', rowContext);
let token: number;
onMounted(() => {
token = ResponsiveObserve.subscribe(screen => {
const currentGutter = gutterRef.value || 0;
if (
(!Array.isArray(currentGutter) && typeof currentGutter === 'object') ||
(Array.isArray(currentGutter) &&
(typeof currentGutter[0] === 'object' || typeof currentGutter[1] === 'object'))
) {
screens.value = screen;
}
});
});
onBeforeUnmount(() => {
ResponsiveObserve.unsubscribe(token);
});
const screens = ref<ScreenMap>({
xs: true,
sm: true,
md: true,
lg: true,
xl: true,
xxl: true,
});
const gutterRef = ref<Gutter | [Gutter, Gutter]>();
gutterRef.value = props.gutter;
const configProvider = inject('configProvider', ConfigConsumerProps);
const { getPrefixCls } = configProvider;
const getGutter = (): [number, number] => {
const results: [number, number] = [0, 0];
const { gutter = 0 } = props;
const normalizedGutter = Array.isArray(gutter) ? gutter : [gutter, 0];
normalizedGutter.forEach((g, index) => {
if (typeof g === 'object') {
for (let i = 0; i < responsiveArray.length; i++) {
const breakpoint: Breakpoint = responsiveArray[i];
if (screens.value[breakpoint] && g[breakpoint] !== undefined) {
results[index] = g[breakpoint] as number;
break;
}
}
} else {
results[index] = g || 0;
}
});
return results;
};
return () => {
const {
prefixCls: customizePrefixCls,
justify,
align,
class: className,
style,
...others
} = props;
const prefixCls = getPrefixCls('row', customizePrefixCls);
const gutter = getGutter();
const classes = classNames(
prefixCls,
{
[`${prefixCls}-${justify}`]: justify,
[`${prefixCls}-${align}`]: align,
},
className,
);
const rowStyle = {
...(gutter[0]! > 0
? {
marginLeft: gutter[0]! / -2,
marginRight: gutter[0]! / -2,
}
: {}),
...(gutter[1]! > 0
? {
marginTop: gutter[1]! / -2,
marginBottom: gutter[1]! / 2,
}
: {}),
};
const otherProps = { ...others, style };
delete otherProps.gutter;
rowContext.gutter = gutter;
return (
<div {...otherProps} class={classes} style={rowStyle}>
{slots.default?.()}
</div>
);
};
},
});

View File

@ -1,4 +1,4 @@
import { inject, defineComponent, VNode, VNodeChild } from 'vue';
import { inject, defineComponent, VNodeChild, PropType } from 'vue';
import defaultLocaleData from './default';
export interface LocaleReceiverProps {
@ -11,8 +11,21 @@ interface LocaleInterface {
[key: string]: any;
}
export default defineComponent<LocaleReceiverProps>({
export default defineComponent({
name: 'LocaleReceiver',
props: {
componentName: {
type: String,
},
defaultLocale: {
type: [Object, Function],
},
children: {
type: Function as PropType<
(locale: object, localeCode?: string, fullLocale?: object) => VNodeChild
>,
},
},
setup() {
return {
localeData: inject('localeData', {}),

View File

@ -38,7 +38,9 @@ function setMomentLocale(locale?: Locale) {
const LocaleProvider = defineComponent({
name: 'ALocaleProvider',
props: {
locale: PropTypes.object.def(() => ({})),
locale: {
type: Object,
},
_ANT_MARK__: PropTypes.string,
},
data() {

View File

@ -1,22 +1,15 @@
import { inject, defineComponent, CSSProperties } from 'vue';
import { inject, defineComponent, App } from 'vue';
import { initDefaultProps } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import { filterEmpty } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
export interface SpaceProps {
prefixCls?: string;
class?: any;
style?: CSSProperties | string;
size?: number;
direction?: 'horizontal' | 'vertical';
// No `stretch` since many components do not support that.
align?: 'start' | 'end' | 'center' | 'baseline';
}
export const SpaceSizeType = PropTypes.oneOfType([
PropTypes.number,
PropTypes.oneOf(['small', 'middle', 'large']),
]);
export const SpaceProps = {
prefixCls: PropTypes.string,
align: PropTypes.tuple<'start' | 'end' | 'center' | 'baseline'>(),
size: PropTypes.tuple<'small' | 'middle' | 'large'>(),
direction: PropTypes.tuple<'horizontal' | 'vertical'>(),
};
const spaceSize = {
small: 8,
@ -35,26 +28,25 @@ const Space = (props, { slots }) => {
const configProvider = inject('configProvider', ConfigConsumerProps);
const { align, size, direction, prefixCls: customizePrefixCls } = props;
const getPrefixCls = configProvider.getPrefixCls;
const prefixCls = getPrefixCls('space', customizePrefixCls);
const items = filterEmpty(slots.default?.());
const len = items.length;
const { getPrefixCls } = configProvider;
const prefixCls = getPrefixCls('space', customizePrefixCls);
const items = filterEmpty(slots.default?.());
const len = items.length;
if (len === 0) {
return null;
}
if (len === 0) {
return null;
}
const mergedAlign = align === undefined && direction === 'horizontal' ? 'center' : align;
const mergedAlign = align === undefined && direction === 'horizontal' ? 'center' : align;
const someSpaceClass = {
[prefixCls]: true,
[`${prefixCls}-${direction}`]: true,
// [`${prefixCls}-rtl`]: directionConfig === 'rtl',
[`${prefixCls}-align-${mergedAlign}`]: mergedAlign,
};
const someSpaceClass = {
[prefixCls]: true,
[`${prefixCls}-${direction}`]: true,
[`${prefixCls}-align-${mergedAlign}`]: mergedAlign,
};
const itemClassName = `${prefixCls}-item`;
const marginDirection = 'marginRight'; // directionConfig === 'rtl' ? 'marginLeft' : 'marginRight';
const itemClassName = `${prefixCls}-item`;
const marginDirection = 'marginRight'; // directionConfig === 'rtl' ? 'marginLeft' : 'marginRight';
return (
<div class={someSpaceClass}>

View File

@ -39,8 +39,12 @@ Use Drawer to quickly preview details of an object, such as those in a list.
</template>
</a-list>
<a-drawer width="640" placement="right" :closable="false" :visible="visible" @close="onClose">
<p :style="[pStyle, pStyle2]">User Profile</p>
<p :style="pStyle">Personal</p>
<p :style="[pStyle, pStyle2]">
User Profile
</p>
<p :style="pStyle">
Personal
</p>
<a-row>
<a-col :span="12">
<description-item title="Full Name" content="Lily" />
@ -74,7 +78,9 @@ Use Drawer to quickly preview details of an object, such as those in a list.
</a-col>
</a-row>
<a-divider />
<p :style="pStyle">Company</p>
<p :style="pStyle">
Company
</p>
<a-row>
<a-col :span="12">
<description-item title="Position" content="Programmer" />
@ -104,7 +110,9 @@ Use Drawer to quickly preview details of an object, such as those in a list.
</a-col>
</a-row>
<a-divider />
<p :style="pStyle">Contacts</p>
<p :style="pStyle">
Contacts
</p>
<a-row>
<a-col :span="12">
<description-item title="Email" content="ant-design-vue@example.com" />
@ -117,9 +125,9 @@ Use Drawer to quickly preview details of an object, such as those in a list.
<a-col :span="24">
<description-item title="Github">
<template v-slot:content>
<a href="https://github.com/vueComponent/ant-design-vue"
>github.com/vueComponent/ant-design-vue</a
>
<a
href="https://github.com/vueComponent/ant-design-vue"
>github.com/vueComponent/ant-design-vue</a>
</template>
</description-item>
</a-col>

View File

@ -1,21 +1,8 @@
import '@babel/polyfill';
import 'ant-design-vue/style.js';
import { createApp, version } from 'vue';
import App from './App.vue';
import antd from 'ant-design-vue/index.js';
// eslint-disable-next-line no-console
console.log('Vue version: ', version);
const basic = (_, { slots }) => {
return slots && slots.default && slots.default();
};
const app = createApp(App);
app
.component('demo-sort', basic)
.component('md', basic)
.component('api', basic)
.component('CN', basic)
.component('US', basic)
.component('demo-container', basic)
.use(antd)
.mount('#app');
app.mount('#app');

View File

@ -76,6 +76,7 @@
"@babel/plugin-transform-template-literals": "^7.8.3",
"@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.9.6",
"@babel/preset-typescript": "^7.10.4",
"@commitlint/cli": "^8.0.0",
"@commitlint/config-conventional": "^8.0.0",
"@octokit/rest": "^16.0.0",
@ -159,6 +160,7 @@
"stylelint-config-standard": "^19.0.0",
"terser-webpack-plugin": "^3.0.3",
"through2": "^3.0.0",
"ts-loader": "^8.0.2",
"typescript": "^3.9.7",
"umi-mock-middleware": "^1.0.0",
"umi-request": "^1.3.5",

View File

@ -4,6 +4,44 @@ const WebpackBar = require('webpackbar');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const babelConfig = {
cacheDirectory: true,
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
},
},
],
'@babel/preset-typescript',
],
plugins: [
[
'babel-plugin-import',
{
libraryName: 'ant-design-vue',
libraryDirectory: '', // default: lib
style: true,
},
],
['@ant-design-vue/babel-plugin-jsx', { optimize: true }],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-class-properties',
],
};
module.exports = {
mode: 'development',
entry: {
@ -20,46 +58,27 @@ module.exports = {
test: /\.(en-US.md|zh-CN.md)$/,
use: [{ loader: 'vue-loader' }, { loader: './loader.js' }],
},
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: babelConfig,
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
exclude: /node_modules/,
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /pickr.*js/,
options: {
cacheDirectory: true,
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4',
],
},
},
],
],
plugins: [
[
'babel-plugin-import',
{
libraryName: 'ant-design-vue',
libraryDirectory: '', // default: lib
style: true,
},
],
['@ant-design-vue/babel-plugin-jsx', { transformOn: true, usePatchFlag: false }],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-class-properties',
],
},
options: babelConfig,
},
{
test: /\.(png|jpg|gif|svg)$/,
@ -115,7 +134,7 @@ module.exports = {
vue$: 'vue/dist/vue.esm-bundler.js',
},
extensions: ['.js', '.jsx', '.vue', '.md'],
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.md'],
},
devServer: {
historyApiFallback: {