chore: refactor space
parent
07d27b057a
commit
4af81c412c
|
@ -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`);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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;
|
||||
}}
|
||||
|
|
|
@ -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>;
|
||||
},
|
||||
};
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
};
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -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', {}),
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue