[improvement] rename packages dir to src (#3659)

This commit is contained in:
neverland
2019-06-27 11:25:57 +08:00
committed by GitHub
parent 8489918dca
commit 75c79b7044
619 changed files with 21 additions and 21 deletions
+27
View File
@@ -0,0 +1,27 @@
/**
* Bind event when mounted or activated
*/
import { on, off } from '../utils/dom/event';
export function BindEventMixin(handler) {
function bind() {
if (!this.binded) {
handler.call(this, on, true);
this.binded = true;
}
}
function unbind() {
if (this.binded) {
handler.call(this, off, false);
this.binded = false;
}
}
return {
mounted: bind,
activated: bind,
deactivated: unbind,
beforeDestroy: unbind
};
}
+95
View File
@@ -0,0 +1,95 @@
/**
* Common part of Checkbox & Radio
*/
import Icon from '../icon';
import { ChildrenMixin } from './relation';
import { suffixPx } from '../utils';
export const CheckboxMixin = ({ parent, bem, role }) => ({
mixins: [ChildrenMixin(parent)],
props: {
name: null,
value: null,
iconSize: [String, Number],
disabled: Boolean,
checkedColor: String,
labelPosition: String,
labelDisabled: Boolean,
shape: {
type: String,
default: 'round'
}
},
computed: {
isDisabled() {
return (this.parent && this.parent.disabled) || this.disabled;
},
iconStyle() {
const { checkedColor } = this;
if (checkedColor && this.checked && !this.isDisabled) {
return {
borderColor: checkedColor,
backgroundColor: checkedColor
};
}
},
tabindex() {
if (this.isDisabled || (role === 'radio' && !this.checked)) {
return -1;
}
return 0;
}
},
render(h) {
const { slots, checked } = this;
const CheckIcon = slots('icon', { checked }) || (
<Icon name="success" style={this.iconStyle} />
);
const Label = slots() && (
<span
class={bem('label', [this.labelPosition, { disabled: this.isDisabled }])}
onClick={this.onClickLabel}
>
{slots()}
</span>
);
const Children = [
<div
class={bem('icon', [this.shape, { disabled: this.isDisabled, checked }])}
style={{ fontSize: suffixPx(this.iconSize) }}
onClick={this.onClickIcon}
>
{CheckIcon}
</div>
];
if (this.labelPosition === 'left') {
Children.unshift(Label);
} else {
Children.push(Label);
}
return (
<div
role={role}
class={bem()}
tabindex={this.tabindex}
aria-checked={String(this.checked)}
onClick={event => {
this.$emit('click', event);
}}
>
{Children}
</div>
);
}
});
+20
View File
@@ -0,0 +1,20 @@
/**
* Listen to click outside event
*/
import { on, off } from '../utils/dom/event';
export const ClickOutsideMixin = config => ({
mounted() {
this.clickOutsideHandler = event => {
if (!this.$el.contains(event.target)) {
this[config.method]();
}
};
on(document, config.event, this.clickOutsideHandler);
},
beforeDestroy() {
off(document, config.event, this.clickOutsideHandler);
}
});
+16
View File
@@ -0,0 +1,16 @@
import { OverlayConfig } from './overlay';
export type StackItem = {
vm: any;
config: OverlayConfig;
};
export const context = {
zIndex: 2000,
lockCount: 0,
stack: [] as StackItem[],
get top(): StackItem {
return this.stack[this.stack.length - 1];
}
};
+191
View File
@@ -0,0 +1,191 @@
import { context } from './context';
import { TouchMixin } from '../touch';
import { PortalMixin } from '../portal';
import { on, off, preventDefault } from '../../utils/dom/event';
import { openOverlay, closeOverlay, updateOverlay } from './overlay';
import { getScrollEventTarget } from '../../utils/dom/scroll';
export const PopupMixin = {
mixins: [
TouchMixin,
PortalMixin({
afterPortal() {
if (this.overlay) {
updateOverlay();
}
}
})
],
props: {
// whether to show popup
value: Boolean,
// whether to show overlay
overlay: Boolean,
// overlay custom style
overlayStyle: Object,
// overlay custom class name
overlayClass: String,
// whether to close popup when click overlay
closeOnClickOverlay: Boolean,
// z-index
zIndex: [String, Number],
// prevent body scroll
lockScroll: {
type: Boolean,
default: true
},
// whether to lazy render
lazyRender: {
type: Boolean,
default: true
}
},
data() {
return {
inited: this.value
};
},
computed: {
shouldRender() {
return this.inited || !this.lazyRender;
}
},
watch: {
value(val) {
const type = val ? 'open' : 'close';
this.inited = this.inited || this.value;
this[type]();
this.$emit(type);
},
overlay() {
this.renderOverlay();
}
},
mounted() {
if (this.value) {
this.open();
}
},
/* istanbul ignore next */
activated() {
if (this.value) {
this.open();
}
},
beforeDestroy() {
this.close();
if (this.getContainer && this.$parent && this.$parent.$el) {
this.$parent.$el.appendChild(this.$el);
}
},
/* istanbul ignore next */
deactivated() {
this.close();
},
methods: {
open() {
/* istanbul ignore next */
if (this.$isServer || this.opened) {
return;
}
// cover default zIndex
if (this.zIndex !== undefined) {
context.zIndex = this.zIndex;
}
this.opened = true;
this.renderOverlay();
if (this.lockScroll) {
on(document, 'touchstart', this.touchStart);
on(document, 'touchmove', this.onTouchMove);
if (!context.lockCount) {
document.body.classList.add('van-overflow-hidden');
}
context.lockCount++;
}
},
close() {
if (!this.opened) {
return;
}
if (this.lockScroll) {
context.lockCount--;
off(document, 'touchstart', this.touchStart);
off(document, 'touchmove', this.onTouchMove);
if (!context.lockCount) {
document.body.classList.remove('van-overflow-hidden');
}
}
this.opened = false;
closeOverlay(this);
this.$emit('input', false);
},
onTouchMove(event) {
this.touchMove(event);
const direction = this.deltaY > 0 ? '10' : '01';
const el = getScrollEventTarget(event.target, this.$el);
const { scrollHeight, offsetHeight, scrollTop } = el;
let status = '11';
/* istanbul ignore next */
if (scrollTop === 0) {
status = offsetHeight >= scrollHeight ? '00' : '01';
} else if (scrollTop + offsetHeight >= scrollHeight) {
status = '10';
}
/* istanbul ignore next */
if (
status !== '11' &&
this.direction === 'vertical' &&
!(parseInt(status, 2) & parseInt(direction, 2))
) {
preventDefault(event, true);
}
},
renderOverlay() {
if (this.$isServer || !this.value) {
return;
}
if (this.overlay) {
openOverlay(this, {
zIndex: context.zIndex++,
duration: this.duration,
className: this.overlayClass,
customStyle: this.overlayStyle
});
} else {
closeOverlay(this);
}
this.updateZIndex();
},
updateZIndex() {
this.$nextTick(() => {
this.$el.style.zIndex = context.zIndex++;
});
}
}
};
+78
View File
@@ -0,0 +1,78 @@
import Overlay from '../../overlay';
import { context } from './context';
import { mount } from '../../utils/functional';
export type OverlayConfig = {
zIndex?: number;
className?: string;
customStyle?: string | object[] | object;
};
const defaultConfig: OverlayConfig = {
className: '',
customStyle: {}
};
let overlay: any;
// close popup when click overlay && closeOnClickOverlay is true
function onClickOverlay(): void {
if (context.top) {
const { vm } = context.top;
vm.$emit('click-overlay');
if (vm.closeOnClickOverlay) {
if (vm.onClickOverlay) {
vm.onClickOverlay();
} else {
vm.close();
}
}
}
}
export function updateOverlay(): void {
if (!overlay) {
overlay = mount(Overlay, {
on: {
click: onClickOverlay
}
});
}
if (context.top) {
const { vm, config } = context.top;
const el = vm.$el;
const target = el && el.parentNode ? el.parentNode : document.body;
if (target) {
target.appendChild(overlay.$el);
}
Object.assign(overlay, defaultConfig, config, {
visible: true
});
} else {
overlay.visible = false;
}
}
export function openOverlay(vm: any, config: OverlayConfig): void {
if (!context.stack.some(item => item.vm === vm)) {
context.stack.push({ vm, config });
updateOverlay();
}
}
export function closeOverlay(vm: any): void {
const { stack } = context;
if (stack.length) {
if (context.top.vm === vm) {
stack.pop();
updateOverlay();
} else {
context.stack = stack.filter(item => item.vm !== vm);
}
}
}
+13
View File
@@ -0,0 +1,13 @@
export type GetContainer = (container: HTMLElement) => void;
export type PopupMixinProps = {
value: boolean;
zIndex: string | number;
overlay?: boolean;
lockScroll: boolean;
lazyRender: boolean;
overlayClass?: any;
overlayStyle?: object | object[];
getContainer?: string | GetContainer;
closeOnClickOverlay?: boolean;
};
+48
View File
@@ -0,0 +1,48 @@
function getElement(selector) {
if (typeof selector === 'string') {
return document.querySelector(selector);
}
return selector();
}
export function PortalMixin({ afterPortal }) {
return {
props: {
getContainer: [String, Function]
},
watch: {
getContainer() {
this.portal();
}
},
mounted() {
if (this.getContainer) {
this.portal();
}
},
methods: {
portal() {
const { getContainer } = this;
let container;
if (getContainer) {
container = getElement(getContainer);
} else if (this.$parent) {
container = this.$parent.$el;
}
if (container && container !== this.$el.parentNode) {
container.appendChild(this.$el);
}
if (afterPortal) {
afterPortal.call(this);
}
}
}
};
}
+68
View File
@@ -0,0 +1,68 @@
export function ChildrenMixin(parent, options = {}) {
const indexKey = options.indexKey || 'index';
return {
inject: {
[parent]: {
default: null
}
},
computed: {
parent() {
return this[parent];
},
[indexKey]() {
this.bindRelation();
return this.parent.children.indexOf(this);
}
},
created() {
this.bindRelation();
},
beforeDestroy() {
if (this.parent) {
this.parent.children = this.parent.children.filter(item => item !== this);
}
},
methods: {
bindRelation() {
if (!this.parent) {
return;
}
const { children } = this.parent;
if (children.indexOf(this) === -1) {
const vnodeIndex = this.parent.slots().indexOf(this.$vnode);
if (vnodeIndex === -1) {
children.push(this);
} else {
children.splice(vnodeIndex, 0, this);
}
}
}
}
};
}
export function ParentMixin(parent) {
return {
provide() {
return {
[parent]: this
};
},
data() {
return {
children: []
};
}
};
}
+16
View File
@@ -0,0 +1,16 @@
/**
* Use scopedSlots in Vue 2.6+
* downgrade to slots in lower version
*/
export const SlotsMixin = {
methods: {
slots(name = 'default', props) {
const { $slots, $scopedSlots } = this;
if ($scopedSlots[name]) {
return $scopedSlots[name](props);
}
return $slots[name];
}
}
};
+43
View File
@@ -0,0 +1,43 @@
const MIN_DISTANCE = 10;
function getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return 'horizontal';
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical';
}
return '';
}
export const TouchMixin = {
data() {
return {
direction: ''
};
},
methods: {
touchStart(event) {
this.resetTouchStatus();
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
},
touchMove(event) {
const touch = event.touches[0];
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || getDirection(this.offsetX, this.offsetY);
},
resetTouchStatus() {
this.direction = '';
this.deltaX = 0;
this.deltaY = 0;
this.offsetX = 0;
this.offsetY = 0;
}
}
};