first commit

This commit is contained in:
编码猿
2024-09-27 00:57:27 +08:00
commit 18df0f5e4b
2548 changed files with 253280 additions and 0 deletions

1
iview/src/.pydio Normal file
View File

@@ -0,0 +1 @@
cc1105a5-6a5b-4b71-b415-f6b3625ac12f

View File

@@ -0,0 +1 @@
9ef31648-8c69-4f80-bd65-43e9b444078f

View File

@@ -0,0 +1 @@
bcc36d6d-e64f-421f-8197-890f1fdfa584

View File

@@ -0,0 +1,148 @@
<template>
<div>
<div ref="point" :class="classes" :style="styles">
<slot></slot>
</div>
<div v-show="slot" :style="slotStyle"></div>
</div>
</template>
<script>
import { on, off } from '../../utils/dom';
const prefixCls = 'ivu-affix';
function getScroll(target, top) {
const prop = top ? 'pageYOffset' : 'pageXOffset';
const method = top ? 'scrollTop' : 'scrollLeft';
let ret = target[prop];
if (typeof ret !== 'number') {
ret = window.document.documentElement[method];
}
return ret;
}
function getOffset(element) {
const rect = element.getBoundingClientRect();
const scrollTop = getScroll(window, true);
const scrollLeft = getScroll(window);
const docEl = window.document.body;
const clientTop = docEl.clientTop || 0;
const clientLeft = docEl.clientLeft || 0;
return {
top: rect.top + scrollTop - clientTop,
left: rect.left + scrollLeft - clientLeft
};
}
export default {
name: 'Affix',
props: {
offsetTop: {
type: Number,
default: 0
},
offsetBottom: {
type: Number
},
useCapture: {
type: Boolean,
default: false
}
},
data () {
return {
affix: false,
styles: {},
slot: false,
slotStyle: {}
};
},
computed: {
offsetType () {
let type = 'top';
if (this.offsetBottom >= 0) {
type = 'bottom';
}
return type;
},
classes () {
return [
{
[`${prefixCls}`]: this.affix
}
];
}
},
mounted () {
// window.addEventListener('scroll', this.handleScroll, false);
// window.addEventListener('resize', this.handleScroll, false);
on(window, 'scroll', this.handleScroll, this.useCapture);
on(window, 'resize', this.handleScroll, this.useCapture);
this.$nextTick(() => {
this.handleScroll();
});
},
beforeDestroy () {
// window.removeEventListener('scroll', this.handleScroll, false);
// window.removeEventListener('resize', this.handleScroll, false);
off(window, 'scroll', this.handleScroll, this.useCapture);
off(window, 'resize', this.handleScroll, this.useCapture);
},
methods: {
handleScroll () {
const affix = this.affix;
const scrollTop = getScroll(window, true);
const elOffset = getOffset(this.$el);
const windowHeight = window.innerHeight;
const elHeight = this.$el.getElementsByTagName('div')[0].offsetHeight;
// Fixed Top
if ((elOffset.top - this.offsetTop) < scrollTop && this.offsetType == 'top' && !affix) {
this.affix = true;
this.slotStyle = {
width: this.$refs.point.clientWidth + 'px',
height: this.$refs.point.clientHeight + 'px'
};
this.slot = true;
this.styles = {
top: `${this.offsetTop}px`,
left: `${elOffset.left}px`,
width: `${this.$el.offsetWidth}px`
};
this.$emit('on-change', true);
} else if ((elOffset.top - this.offsetTop) > scrollTop && this.offsetType == 'top' && affix) {
this.slot = false;
this.slotStyle = {};
this.affix = false;
this.styles = null;
this.$emit('on-change', false);
}
// Fixed Bottom
if ((elOffset.top + this.offsetBottom + elHeight) > (scrollTop + windowHeight) && this.offsetType == 'bottom' && !affix) {
this.affix = true;
this.styles = {
bottom: `${this.offsetBottom}px`,
left: `${elOffset.left}px`,
width: `${this.$el.offsetWidth}px`
};
this.$emit('on-change', true);
} else if ((elOffset.top + this.offsetBottom + elHeight) < (scrollTop + windowHeight) && this.offsetType == 'bottom' && affix) {
this.affix = false;
this.styles = null;
this.$emit('on-change', false);
}
}
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Affix from './affix.vue';
export default Affix;

View File

@@ -0,0 +1 @@
ed4338ee-aa4a-4ef7-afea-7d3c00ecfa07

View File

@@ -0,0 +1,110 @@
<template>
<transition name="fade">
<div v-if="!closed" :class="wrapClasses">
<span :class="iconClasses" v-if="showIcon">
<slot name="icon">
<Icon :type="iconType"></Icon>
</slot>
</span>
<span :class="messageClasses"><slot></slot></span>
<span :class="descClasses"><slot name="desc"></slot></span>
<a :class="closeClasses" v-if="closable" @click="close">
<slot name="close">
<Icon type="ios-close"></Icon>
</slot>
</a>
</div>
</transition>
</template>
<script>
import Icon from '../icon';
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-alert';
export default {
name: 'Alert',
components: { Icon },
props: {
type: {
validator (value) {
return oneOf(value, ['success', 'info', 'warning', 'error']);
},
default: 'info'
},
closable: {
type: Boolean,
default: false
},
showIcon: {
type: Boolean,
default: false
},
banner: {
type: Boolean,
default: false
}
},
data () {
return {
closed: false,
desc: false
};
},
computed: {
wrapClasses () {
return [
`${prefixCls}`,
`${prefixCls}-${this.type}`,
{
[`${prefixCls}-with-icon`]: this.showIcon,
[`${prefixCls}-with-desc`]: this.desc,
[`${prefixCls}-with-banner`]: this.banner
}
];
},
messageClasses () {
return `${prefixCls}-message`;
},
descClasses () {
return `${prefixCls}-desc`;
},
closeClasses () {
return `${prefixCls}-close`;
},
iconClasses () {
return `${prefixCls}-icon`;
},
iconType () {
let type = '';
switch (this.type) {
case 'success':
type = 'ios-checkmark-circle';
break;
case 'info':
type = 'ios-information-circle';
break;
case 'warning':
type = 'ios-alert';
break;
case 'error':
type = 'ios-close-circle';
break;
}
if (this.desc) type += '-outline';
return type;
}
},
methods: {
close (e) {
this.closed = true;
this.$emit('on-close', e);
}
},
mounted () {
this.desc = this.$slots.desc !== undefined;
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Alert from './alert.vue';
export default Alert;

View File

@@ -0,0 +1 @@
ea337167-fb7a-4bb9-a505-4e2fc78390f5

View File

@@ -0,0 +1,2 @@
import AnchorLink from '../anchor/anchor-link.vue';
export default AnchorLink;

View File

@@ -0,0 +1 @@
226730d2-46d8-4467-b7f8-9150367abc82

View File

@@ -0,0 +1,59 @@
<template>
<div :class="anchorLinkClasses">
<a :class="linkTitleClasses" :href="href" :data-scroll-offset="scrollOffset" :data-href="href" @click.prevent="goAnchor" :title="title">{{ title }}</a>
<slot></slot>
</div>
</template>
<script>
export default {
name: 'AnchorLink',
inject: ['anchorCom'],
props: {
href: String,
title: String,
scrollOffset: {
type: Number,
default () {
return this.anchorCom.scrollOffset;
}
}
},
data () {
return {
prefix: 'ivu-anchor-link'
};
},
computed: {
anchorLinkClasses () {
return [
this.prefix,
this.anchorCom.currentLink === this.href ? `${this.prefix}-active` : ''
];
},
linkTitleClasses () {
return [
`${this.prefix}-title`
];
}
},
methods: {
goAnchor () {
this.currentLink = this.href;
this.anchorCom.handleHashChange();
this.anchorCom.handleScrollTo();
this.anchorCom.$emit('on-select', this.href);
const isRoute = this.$router;
if (isRoute) {
this.$router.push(this.href);
} else {
window.location.href = this.href;
}
}
},
mounted () {
this.$nextTick(() => {
this.anchorCom.init();
});
}
};
</script>

View File

@@ -0,0 +1,200 @@
<template>
<component :is="wrapperComponent" :offset-top="offsetTop" :offset-bottom="offsetBottom" @on-change="handleAffixStateChange">
<div :class="`${prefix}-wrapper`" :style="wrapperStyle">
<div :class="`${prefix}`">
<div :class="`${prefix}-ink`">
<span v-show="showInk" :class="`${prefix}-ink-ball`" :style="{top: `${inkTop}px`}"></span>
</div>
<slot></slot>
</div>
</div>
</component>
</template>
<script>
import { scrollTop, findComponentsDownward, sharpMatcherRegx } from '../../utils/assist';
import { on, off } from '../../utils/dom';
export default {
name: 'Anchor',
provide () {
return {
anchorCom: this
};
},
data () {
return {
prefix: 'ivu-anchor',
isAffixed: false, // current affixed state
inkTop: 0,
animating: false, // if is scrolling now
currentLink: '', // current show link => #href -> currentLink = #href
currentId: '', // current show title id => #href -> currentId = href
scrollContainer: null,
scrollElement: null,
titlesOffsetArr: [],
wrapperTop: 0,
upperFirstTitle: true
};
},
props: {
affix: {
type: Boolean,
default: true
},
offsetTop: {
type: Number,
default: 0
},
offsetBottom: Number,
bounds: {
type: Number,
default: 5
},
// container: [String, HTMLElement], // HTMLElement 在 SSR 下不支持
container: null,
showInk: {
type: Boolean,
default: false
},
scrollOffset: {
type: Number,
default: 0
}
},
computed: {
wrapperComponent () {
return this.affix ? 'Affix' : 'div';
},
wrapperStyle () {
return {
maxHeight: this.offsetTop ? `calc(100vh - ${this.offsetTop}px)` : '100vh'
};
},
containerIsWindow () {
return this.scrollContainer === window;
}
},
methods: {
handleAffixStateChange (state) {
this.isAffixed = this.affix && state;
},
handleScroll (e) {
this.upperFirstTitle = e.target.scrollTop < this.titlesOffsetArr[0].offset;
if (this.animating) return;
this.updateTitleOffset();
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop || e.target.scrollTop;
this.getCurrentScrollAtTitleId(scrollTop);
},
handleHashChange () {
const url = window.location.href;
const sharpLinkMatch = sharpMatcherRegx.exec(url);
if (!sharpLinkMatch) return;
this.currentLink = sharpLinkMatch[0];
this.currentId = sharpLinkMatch[1];
},
handleScrollTo () {
const anchor = document.getElementById(this.currentId);
const currentLinkElementA = document.querySelector(`a[data-href="${this.currentLink}"]`);
let offset = this.scrollOffset;
if (currentLinkElementA) {
offset = parseFloat(currentLinkElementA.getAttribute('data-scroll-offset'));
}
if (!anchor) return;
const offsetTop = anchor.offsetTop - this.wrapperTop - offset;
this.animating = true;
scrollTop(this.scrollContainer, this.scrollElement.scrollTop, offsetTop, 600, () => {
this.animating = false;
});
this.handleSetInkTop();
},
handleSetInkTop () {
const currentLinkElementA = document.querySelector(`a[data-href="${this.currentLink}"]`);
if (!currentLinkElementA) return;
const elementATop = currentLinkElementA.offsetTop;
const top = (elementATop < 0 ? this.offsetTop : elementATop);
this.inkTop = top;
},
updateTitleOffset () {
const links = findComponentsDownward(this, 'AnchorLink').map(link => {
return link.href;
});
const idArr = links.map(link => {
return link.split('#')[1];
});
let offsetArr = [];
idArr.forEach(id => {
const titleEle = document.getElementById(id);
if (titleEle) offsetArr.push({
link: `#${id}`,
offset: titleEle.offsetTop - this.scrollElement.offsetTop
});
});
this.titlesOffsetArr = offsetArr;
},
getCurrentScrollAtTitleId (scrollTop) {
let i = -1;
let len = this.titlesOffsetArr.length;
let titleItem = {
link: '#',
offset: 0
};
scrollTop += this.bounds;
while (++i < len) {
let currentEle = this.titlesOffsetArr[i];
let nextEle = this.titlesOffsetArr[i + 1];
if (scrollTop >= currentEle.offset && scrollTop < ((nextEle && nextEle.offset) || Infinity)) {
titleItem = this.titlesOffsetArr[i];
break;
}
}
this.currentLink = titleItem.link;
this.handleSetInkTop();
},
getContainer () {
this.scrollContainer = this.container ? (typeof this.container === 'string' ? document.querySelector(this.container) : this.container) : window;
this.scrollElement = this.container ? this.scrollContainer : (document.documentElement || document.body);
},
removeListener () {
off(this.scrollContainer, 'scroll', this.handleScroll);
off(window, 'hashchange', this.handleHashChange);
},
init () {
// const anchorLink = findComponentDownward(this, 'AnchorLink');
this.handleHashChange();
this.$nextTick(() => {
this.removeListener();
this.getContainer();
this.wrapperTop = this.containerIsWindow ? 0 : this.scrollElement.offsetTop;
this.handleScrollTo();
this.handleSetInkTop();
this.updateTitleOffset();
if (this.titlesOffsetArr[0]) {
this.upperFirstTitle = this.scrollElement.scrollTop < this.titlesOffsetArr[0].offset;
}
on(this.scrollContainer, 'scroll', this.handleScroll);
on(window, 'hashchange', this.handleHashChange);
});
}
},
watch: {
'$route' () {
this.handleHashChange();
this.$nextTick(() => {
this.handleScrollTo();
});
},
container () {
this.init();
},
currentLink (newHref, oldHref) {
this.$emit('on-change', newHref, oldHref);
}
},
mounted () {
this.init();
},
beforeDestroy () {
this.removeListener();
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Anchor from './anchor.vue';
export default Anchor;

View File

@@ -0,0 +1 @@
97747c56-1c75-4d4e-a791-7089782c78d8

View File

@@ -0,0 +1,181 @@
<template>
<i-select
ref="select"
class="ivu-auto-complete"
:label="label"
:disabled="disabled"
:clearable="clearable"
:placeholder="placeholder"
:size="size"
:placement="placement"
:value="currentValue"
filterable
remote
auto-complete
:remote-method="remoteMethod"
@on-select="handleSelect"
@on-clickoutside="handleClickOutside"
:transfer="transfer">
<slot name="input">
<i-input
:element-id="elementId"
ref="input"
slot="input"
v-model="currentValue"
:name="name"
:placeholder="placeholder"
:disabled="disabled"
:size="size"
:icon="inputIcon"
@on-click="handleClear"
@on-focus="handleFocus"
@on-blur="handleBlur"></i-input>
</slot>
<slot>
<i-option v-for="item in filteredData" :value="item" :key="item">{{ item }}</i-option>
</slot>
</i-select>
</template>
<script>
import iSelect from '../select/select.vue';
import iOption from '../select/option.vue';
import iInput from '../input/input.vue';
import { oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
export default {
name: 'AutoComplete',
mixins: [ Emitter ],
components: { iSelect, iOption, iInput },
props: {
value: {
type: [String, Number],
default: ''
},
label: {
type: [String, Number],
default: ''
},
data: {
type: Array,
default: () => []
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
placeholder: {
type: String
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
icon: {
type: String
},
filterMethod: {
type: [Function, Boolean],
default: false
},
placement: {
validator (value) {
return oneOf(value, ['top', 'bottom', 'top-start', 'bottom-start', 'top-end', 'bottom-end']);
},
default: 'bottom'
},
transfer: {
type: Boolean,
default () {
return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
}
},
name: {
type: String
},
elementId: {
type: String
}
},
data () {
return {
currentValue: this.value,
disableEmitChange: false // for Form reset
};
},
computed: {
inputIcon () {
let icon = '';
//#6161 #7
if (this.clearable && this.currentValue && !this.disabled) {
icon = 'ios-close';
} else if (this.icon) {
icon = this.icon;
}
return icon;
},
filteredData () {
if (this.filterMethod) {
return this.data.filter(item => this.filterMethod(this.currentValue, item));
} else {
return this.data;
}
}
},
watch: {
value (val) {
if(this.currentValue !== val){
this.disableEmitChange = true;
}
this.currentValue = val;
},
currentValue (val) {
this.$refs.select.setQuery(val);
this.$emit('input', val);
if (this.disableEmitChange) {
this.disableEmitChange = false;
return;
}
this.$emit('on-change', val);
this.dispatch('FormItem', 'on-form-change', val);
}
},
methods: {
remoteMethod (query) {
this.$emit('on-search', query);
},
handleSelect (val) {
if (val === undefined || val === null) return;
this.currentValue = val;
this.$refs.input.blur();
this.$emit('on-select', val);
},
handleFocus (event) {
this.$emit('on-focus', event);
},
handleBlur (event) {
this.$emit('on-blur', event);
},
handleClear () {
if (!this.clearable) return;
this.currentValue = '';
this.$refs.select.reset();
this.$emit('on-clear');
},
handleClickOutside(){
this.$nextTick(() => {
this.$refs.input.blur();
});
}
}
};
</script>

View File

@@ -0,0 +1,2 @@
import AutoComplete from './auto-complete.vue';
export default AutoComplete;

View File

@@ -0,0 +1 @@
bc6a9cf8-acdc-4ba4-9ec5-a51ea65b6cea

View File

@@ -0,0 +1,104 @@
<template>
<span :class="classes">
<img :src="src" v-if="src" @error="handleError">
<Icon :type="icon" :custom="customIcon" v-else-if="icon || customIcon"></Icon>
<span ref="children" :class="[prefixCls + '-string']" :style="childrenStyle" v-else><slot></slot></span>
</span>
</template>
<script>
import Icon from '../icon';
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-avatar';
export default {
name: 'Avatar',
components: { Icon },
props: {
shape: {
validator (value) {
return oneOf(value, ['circle', 'square']);
},
default: 'circle'
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
src: {
type: String
},
icon: {
type: String
},
customIcon: {
type: String,
default: ''
},
},
data () {
return {
prefixCls: prefixCls,
scale: 1,
childrenWidth: 0,
isSlotShow: false
};
},
computed: {
classes () {
return [
`${prefixCls}`,
`${prefixCls}-${this.shape}`,
`${prefixCls}-${this.size}`,
{
[`${prefixCls}-image`]: !!this.src,
[`${prefixCls}-icon`]: !!this.icon || !!this.customIcon
}
];
},
childrenStyle () {
let style = {};
if (this.isSlotShow) {
style = {
msTransform: `scale(${this.scale})`,
WebkitTransform: `scale(${this.scale})`,
transform: `scale(${this.scale})`,
position: 'absolute',
display: 'inline-block',
left: `calc(50% - ${Math.round(this.childrenWidth / 2)}px)`
};
}
return style;
}
},
methods: {
setScale () {
this.isSlotShow = !this.src && !this.icon;
if (this.$refs.children) {
// set children width again to make slot centered
this.childrenWidth = this.$refs.children.offsetWidth;
const avatarWidth = this.$el.getBoundingClientRect().width;
// add 4px gap for each side to get better performance
if (avatarWidth - 8 < this.childrenWidth) {
this.scale = (avatarWidth - 8) / this.childrenWidth;
} else {
this.scale = 1;
}
}
},
handleError (e) {
this.$emit('on-error', e);
}
},
mounted () {
this.setScale();
},
updated () {
this.setScale();
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Avatar from './avatar.vue';
export default Avatar;

View File

@@ -0,0 +1 @@
6f5ed15d-f925-4e89-aefa-066950caf651

View File

@@ -0,0 +1,81 @@
<template>
<div :class="classes" :style="styles" @click="back">
<slot>
<div :class="innerClasses">
<i class="ivu-icon ivu-icon-ios-arrow-up"></i>
</div>
</slot>
</div>
</template>
<script>
import { scrollTop } from '../../utils/assist';
import { on, off } from '../../utils/dom';
const prefixCls = 'ivu-back-top';
export default {
props: {
height: {
type: Number,
default: 400
},
bottom: {
type: Number,
default: 30
},
right: {
type: Number,
default: 30
},
duration: {
type: Number,
default: 1000
}
},
data () {
return {
backTop: false
};
},
mounted () {
// window.addEventListener('scroll', this.handleScroll, false);
// window.addEventListener('resize', this.handleScroll, false);
on(window, 'scroll', this.handleScroll);
on(window, 'resize', this.handleScroll);
},
beforeDestroy () {
// window.removeEventListener('scroll', this.handleScroll, false);
// window.removeEventListener('resize', this.handleScroll, false);
off(window, 'scroll', this.handleScroll);
off(window, 'resize', this.handleScroll);
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-show`]: this.backTop
}
];
},
styles () {
return {
bottom: `${this.bottom}px`,
right: `${this.right}px`
};
},
innerClasses () {
return `${prefixCls}-inner`;
}
},
methods: {
handleScroll () {
this.backTop = window.pageYOffset >= this.height;
},
back () {
const sTop = document.documentElement.scrollTop || document.body.scrollTop;
scrollTop(window, sTop, 0, this.duration);
this.$emit('on-click');
}
}
};
</script>

View File

@@ -0,0 +1,2 @@
import BackTop from './back-top.vue';
export default BackTop;

View File

@@ -0,0 +1 @@
76101f31-c6da-4697-ba63-c08a6afa12ad

View File

@@ -0,0 +1,121 @@
<template>
<span v-if="dot" :class="classes" ref="badge">
<slot></slot>
<sup :class="dotClasses" :style="styles" v-show="badge"></sup>
</span>
<span v-else-if="status" :class="classes" class="ivu-badge-status" ref="badge">
<span :class="statusClasses"></span>
<span class="ivu-badge-status-text">{{ text }}</span>
</span>
<span v-else :class="classes" ref="badge">
<slot></slot>
<sup v-if="hasCount" :style="styles" :class="countClasses" v-show="badge">{{ finalCount }}</sup>
</span>
</template>
<script>
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-badge';
export default {
name: 'Badge',
props: {
count: Number,
dot: {
type: Boolean,
default: false
},
overflowCount: {
type: [Number, String],
default: 99
},
className: String,
showZero: {
type: Boolean,
default: false
},
text: {
type: String,
default: ''
},
status: {
validator (value) {
return oneOf(value, ['success', 'processing', 'default', 'error', 'warning']);
}
},
type: {
validator (value) {
return oneOf(value, ['success', 'primary', 'normal', 'error', 'warning', 'info']);
}
},
offset: {
type: Array
}
},
computed: {
classes () {
return `${prefixCls}`;
},
dotClasses () {
return `${prefixCls}-dot`;
},
countClasses () {
return [
`${prefixCls}-count`,
{
[`${this.className}`]: !!this.className,
[`${prefixCls}-count-alone`]: this.alone,
[`${prefixCls}-count-${this.type}`]: !!this.type
}
];
},
statusClasses () {
return [
`${prefixCls}-status-dot`,
{
[`${prefixCls}-status-${this.status}`]: !!this.status
}
];
},
styles () {
const style = {};
if (this.offset && this.offset.length === 2) {
style['margin-top'] = `${this.offset[0]}px`;
style['margin-right'] = `${this.offset[1]}px`;
}
return style;
},
finalCount () {
if (this.text !== '') return this.text;
return parseInt(this.count) >= parseInt(this.overflowCount) ? `${this.overflowCount}+` : this.count;
},
badge () {
let status = false;
if (this.count) {
status = !(parseInt(this.count) === 0);
}
if (this.dot) {
status = true;
if (this.count !== null) {
if (parseInt(this.count) === 0) {
status = false;
}
}
}
if (this.text !== '') status = true;
return status || this.showZero;
},
hasCount() {
if(this.count || this.text !== '') return true;
if(this.showZero && parseInt(this.count) === 0) return true;
else return false;
},
alone () {
return this.$slots.default === undefined;
}
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Badge from './badge.vue';
export default Badge;

View File

@@ -0,0 +1 @@
1fb482dc-c6f4-4e36-b6c7-69dcb85b654b

View File

@@ -0,0 +1,83 @@
import { addClass, removeClass } from '../../utils/assist';
const Transition = {
beforeEnter(el) {
addClass(el, 'collapse-transition');
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
el.style.overflow = 'hidden';
},
afterEnter(el) {
// for safari: remove class then reset height is necessary
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
leave(el) {
if (el.scrollHeight !== 0) {
// for safari: add class after set height, or it will jump to zero height suddenly, weired
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
afterLeave(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
};
export default {
name: 'CollapseTransition',
functional: true,
props: {
appear: Boolean
},
render(h, { children, props }) {
const data = {
on: Transition,
props: {
appear: props.appear
}
};
return h('transition', data, children);
}
};

View File

@@ -0,0 +1 @@
a2ac206e-b712-4562-8bcd-1e0af0c1e475

View File

@@ -0,0 +1,36 @@
import Notification from './notification.vue';
import Vue from 'vue';
Notification.newInstance = properties => {
const _props = properties || {};
const Instance = new Vue({
render (h) {
return h(Notification, {
props: _props
});
}
});
const component = Instance.$mount();
document.body.appendChild(component.$el);
const notification = Instance.$children[0];
return {
notice (noticeProps) {
notification.add(noticeProps);
},
remove (name) {
notification.close(name);
},
component: notification,
destroy (element) {
notification.closeAll();
setTimeout(function() {
document.body.removeChild(document.getElementsByClassName(element)[0]);
}, 500);
}
};
};
export default Notification;

View File

@@ -0,0 +1,172 @@
<template>
<transition :name="transitionName" @enter="handleEnter" @leave="handleLeave" appear>
<div :class="classes" :style="styles">
<template v-if="type === 'notice'">
<div :class="contentClasses" ref="content" v-html="content"></div>
<div :class="contentWithIcon">
<render-cell
:render="renderFunc"
></render-cell>
</div>
<a :class="[baseClass + '-close']" @click="close" v-if="closable">
<i class="ivu-icon ivu-icon-ios-close"></i>
</a>
</template>
<template v-if="type === 'message'">
<div :class="[baseClass + '-content']" ref="content">
<div :class="[baseClass + '-content-text']" v-html="content"></div>
<div :class="[baseClass + '-content-text']">
<render-cell
:render="renderFunc"
></render-cell>
</div>
<a :class="[baseClass + '-close']" @click="close" v-if="closable">
<i class="ivu-icon ivu-icon-ios-close"></i>
</a>
</div>
</template>
</div>
</transition>
</template>
<script>
import RenderCell from '../render';
export default {
components: {
RenderCell
},
props: {
prefixCls: {
type: String,
default: ''
},
duration: {
type: Number,
default: 1.5
},
type: {
type: String
},
content: {
type: String,
default: ''
},
withIcon: Boolean,
render: {
type: Function
},
hasTitle: Boolean,
styles: {
type: Object,
default: function() {
return {
right: '50%'
};
}
},
closable: {
type: Boolean,
default: false
},
className: {
type: String
},
name: {
type: String,
required: true
},
onClose: {
type: Function
},
transitionName: {
type: String
}
},
data () {
return {
withDesc: false
};
},
computed: {
baseClass () {
return `${this.prefixCls}-notice`;
},
renderFunc () {
return this.render || function () {};
},
classes () {
return [
this.baseClass,
{
[`${this.className}`]: !!this.className,
[`${this.baseClass}-closable`]: this.closable,
[`${this.baseClass}-with-desc`]: this.withDesc
}
];
},
contentClasses () {
return [
`${this.baseClass}-content`,
this.render !== undefined ? `${this.baseClass}-content-with-render` : ''
];
},
contentWithIcon () {
return [
this.withIcon ? `${this.prefixCls}-content-with-icon` : '',
!this.hasTitle && this.withIcon ? `${this.prefixCls}-content-with-render-notitle` : ''
];
},
messageClasses () {
return [
`${this.baseClass}-content`,
this.render !== undefined ? `${this.baseClass}-content-with-render` : ''
];
}
},
methods: {
clearCloseTimer () {
if (this.closeTimer) {
clearTimeout(this.closeTimer);
this.closeTimer = null;
}
},
close () {
this.clearCloseTimer();
this.onClose();
this.$parent.close(this.name);
},
handleEnter (el) {
if (this.type === 'message') {
el.style.height = el.scrollHeight + 'px';
}
},
handleLeave (el) {
if (this.type === 'message') {
// 优化一下,如果当前只有一个 Message则不使用 js 过渡动画,这样更优美
if (document.getElementsByClassName('ivu-message-notice').length !== 1) {
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
}
}
},
mounted () {
this.clearCloseTimer();
if (this.duration !== 0) {
this.closeTimer = setTimeout(() => {
this.close();
}, this.duration * 1000);
}
// check if with desc in Notice component
if (this.prefixCls === 'ivu-notice') {
let desc = this.$refs.content.querySelectorAll(`.${this.prefixCls}-desc`)[0];
this.withDesc = this.render ? true : (desc ? desc.innerHTML !== '' : false);
}
},
beforeDestroy () {
this.clearCloseTimer();
}
};
</script>

View File

@@ -0,0 +1,114 @@
<template>
<div :class="classes" :style="wrapStyles">
<Notice
v-for="notice in notices"
:key="notice.name"
:prefix-cls="prefixCls"
:styles="notice.styles"
:type="notice.type"
:content="notice.content"
:duration="notice.duration"
:render="notice.render"
:has-title="notice.hasTitle"
:withIcon="notice.withIcon"
:closable="notice.closable"
:name="notice.name"
:transition-name="notice.transitionName"
:on-close="notice.onClose">
</Notice>
</div>
</template>
<script>
import Notice from './notice.vue';
import { transferIndex, transferIncrease } from '../../../utils/transfer-queue';
const prefixCls = 'ivu-notification';
let seed = 0;
const now = Date.now();
function getUuid () {
return 'ivuNotification_' + now + '_' + (seed++);
}
export default {
components: { Notice },
props: {
prefixCls: {
type: String,
default: prefixCls
},
styles: {
type: Object,
default: function () {
return {
top: '65px',
left: '50%'
};
}
},
content: {
type: String
},
className: {
type: String
}
},
data () {
return {
notices: [],
tIndex: this.handleGetIndex()
};
},
computed: {
classes () {
return [
`${this.prefixCls}`,
{
[`${this.className}`]: !!this.className
}
];
},
wrapStyles () {
let styles = Object.assign({}, this.styles);
styles['z-index'] = 1010 + this.tIndex;
return styles;
}
},
methods: {
add (notice) {
const name = notice.name || getUuid();
let _notice = Object.assign({
styles: {
right: '50%'
},
content: '',
duration: 1.5,
closable: false,
name: name
}, notice);
this.notices.push(_notice);
this.tIndex = this.handleGetIndex();
},
close (name) {
const notices = this.notices;
for (let i = 0; i < notices.length; i++) {
if (notices[i].name === name) {
this.notices.splice(i, 1);
break;
}
}
},
closeAll () {
this.notices = [];
},
handleGetIndex () {
transferIncrease();
return transferIndex;
},
}
};
</script>

View File

@@ -0,0 +1,124 @@
/**
* https://github.com/freeze-component/vue-popper
* */
import Vue from 'vue';
const isServer = Vue.prototype.$isServer;
const Popper = isServer ? function() {} : require('popper.js/dist/umd/popper.js'); // eslint-disable-line
export default {
props: {
placement: {
type: String,
default: 'bottom'
},
boundariesPadding: {
type: Number,
default: 5
},
reference: Object,
popper: Object,
offset: {
default: 0
},
value: {
type: Boolean,
default: false
},
transition: String,
options: {
type: Object,
default () {
return {
modifiers: {
computeStyle:{
gpuAcceleration: false,
},
preventOverflow :{
boundariesElement: 'window'
}
}
};
}
},
// visible: {
// type: Boolean,
// default: false
// }
},
data () {
return {
visible: this.value
};
},
watch: {
value: {
immediate: true,
handler(val) {
this.visible = val;
this.$emit('input', val);
}
},
visible(val) {
if (val) {
if (this.handleIndexIncrease) this.handleIndexIncrease(); // just use for Poptip
this.updatePopper();
this.$emit('on-popper-show');
} else {
this.$emit('on-popper-hide');
}
this.$emit('input', val);
}
},
methods: {
createPopper() {
if (isServer) return;
if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
return;
}
const options = this.options;
const popper = this.popper || this.$refs.popper;
const reference = this.reference || this.$refs.reference;
if (!popper || !reference) return;
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
this.popperJS.destroy();
}
options.placement = this.placement;
if (!options.modifiers.offset) {
options.modifiers.offset = {};
}
options.modifiers.offset.offset = this.offset;
options.onCreate =()=>{
this.$nextTick(this.updatePopper);
this.$emit('created', this);
};
this.popperJS = new Popper(reference, popper, options);
},
updatePopper() {
if (isServer) return;
this.popperJS ? this.popperJS.update() : this.createPopper();
},
doDestroy() {
if (isServer) return;
if (this.visible) return;
this.popperJS.destroy();
this.popperJS = null;
}
},
updated (){
this.$nextTick(()=>this.updatePopper());
},
beforeDestroy() {
if (isServer) return;
if (this.popperJS) {
this.popperJS.destroy();
}
}
};

View File

@@ -0,0 +1,10 @@
export default {
name: 'RenderCell',
functional: true,
props: {
render: Function
},
render: (h, ctx) => {
return ctx.props.render(h);
}
};

View File

@@ -0,0 +1 @@
49ea672c-7ebc-4671-9531-1b60b0d2fb39

View File

@@ -0,0 +1,3 @@
import BreadcrumbItem from '../breadcrumb/breadcrumb-item.vue';
export default BreadcrumbItem;

View File

@@ -0,0 +1 @@
8157997b-3013-408a-8355-f729b890d8ed

View File

@@ -0,0 +1,50 @@
<template>
<span>
<a
v-if="to"
:href="linkUrl"
:target="target"
:class="linkClasses"
@click.exact="handleCheckClick($event, false)"
@click.ctrl="handleCheckClick($event, true)"
@click.meta="handleCheckClick($event, true)">
<slot></slot>
</a>
<span v-else :class="linkClasses">
<slot></slot>
</span>
<span :class="separatorClasses" v-html="separator" v-if="!showSeparator"></span>
<span :class="separatorClasses" v-else>
<slot name="separator"></slot>
</span>
</span>
</template>
<script>
import mixinsLink from '../../mixins/link';
const prefixCls = 'ivu-breadcrumb-item';
export default {
name: 'BreadcrumbItem',
mixins: [ mixinsLink ],
props: {
},
data () {
return {
separator: '',
showSeparator: false
};
},
computed: {
linkClasses () {
return `${prefixCls}-link`;
},
separatorClasses () {
return `${prefixCls}-separator`;
}
},
mounted () {
this.showSeparator = this.$slots.separator !== undefined;
}
};
</script>

View File

@@ -0,0 +1,43 @@
<template>
<div :class="classes">
<slot></slot>
</div>
</template>
<script>
const prefixCls = 'ivu-breadcrumb';
export default {
name: 'Breadcrumb',
props: {
separator: {
type: String,
default: '/'
}
},
computed: {
classes () {
return `${prefixCls}`;
}
},
mounted () {
this.updateChildren();
},
updated () {
this.$nextTick(() => {
this.updateChildren();
});
},
methods: {
updateChildren () {
this.$children.forEach((child) => {
child.separator = this.separator;
});
}
},
watch: {
separator () {
this.updateChildren();
}
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Breadcrumb from './breadcrumb.vue';
import BreadcrumbItem from './breadcrumb-item.vue';
Breadcrumb.Item = BreadcrumbItem;
export default Breadcrumb;

View File

@@ -0,0 +1 @@
24b93a6f-ff0b-491e-8780-51fa23660293

View File

@@ -0,0 +1,3 @@
import ButtonGroup from '../button/button-group.vue';
export default ButtonGroup;

View File

@@ -0,0 +1 @@
0435d638-b3a3-42f4-a835-c77155db4967

View File

@@ -0,0 +1,45 @@
<template>
<div :class="classes">
<slot></slot>
</div>
</template>
<script>
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-btn-group';
export default {
name: 'ButtonGroup',
props: {
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
shape: {
validator (value) {
return oneOf(value, ['circle', 'circle-outline']);
}
},
vertical: {
type: Boolean,
default: false
}
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-${this.size}`]: !!this.size,
[`${prefixCls}-${this.shape}`]: !!this.shape,
[`${prefixCls}-vertical`]: this.vertical
}
];
}
}
};
</script>

View File

@@ -0,0 +1,117 @@
<template>
<component :is="tagName" :class="classes" :disabled="disabled" @click="handleClickLink" v-bind="tagProps">
<Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon>
<Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon>
<span v-if="showSlot" ref="slot"><slot></slot></span>
</component>
</template>
<script>
import Icon from '../icon';
import { oneOf } from '../../utils/assist';
import mixinsLink from '../../mixins/link';
const prefixCls = 'ivu-btn';
export default {
name: 'Button',
mixins: [ mixinsLink ],
components: { Icon },
props: {
type: {
validator (value) {
return oneOf(value, ['default', 'primary', 'dashed', 'text', 'info', 'success', 'warning', 'error']);
},
default: 'default'
},
shape: {
validator (value) {
return oneOf(value, ['circle', 'circle-outline']);
}
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
loading: Boolean,
disabled: Boolean,
htmlType: {
default: 'button',
validator (value) {
return oneOf(value, ['button', 'submit', 'reset']);
}
},
icon: {
type: String,
default: ''
},
customIcon: {
type: String,
default: ''
},
long: {
type: Boolean,
default: false
},
ghost: {
type: Boolean,
default: false
}
},
data () {
return {
showSlot: true
};
},
computed: {
classes () {
return [
`${prefixCls}`,
`${prefixCls}-${this.type}`,
{
[`${prefixCls}-long`]: this.long,
[`${prefixCls}-${this.shape}`]: !!this.shape,
[`${prefixCls}-${this.size}`]: this.size !== 'default',
[`${prefixCls}-loading`]: this.loading != null && this.loading,
[`${prefixCls}-icon-only`]: !this.showSlot && (!!this.icon || !!this.customIcon || this.loading),
[`${prefixCls}-ghost`]: this.ghost
}
];
},
// Point out if it should render as <a> tag
isHrefPattern() {
const {to} = this;
return !!to;
},
tagName() {
const {isHrefPattern} = this;
return isHrefPattern ? 'a' : 'button';
},
tagProps() {
const {isHrefPattern} = this;
if(isHrefPattern) {
const {linkUrl,target}=this;
return {href: linkUrl, target};
} else {
const {htmlType} = this;
return {type: htmlType};
}
}
},
methods: {
// Ctrl or CMD and click, open in new window when use `to`
handleClickLink (event) {
this.$emit('click', event);
const openInNewWindow = event.ctrlKey || event.metaKey;
this.handleCheckClick(event, openInNewWindow);
}
},
mounted () {
this.showSlot = this.$slots.default !== undefined;
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Button from './button.vue';
import ButtonGroup from './button-group.vue';
Button.Group = ButtonGroup;
export default Button;

View File

@@ -0,0 +1 @@
f35ab651-7a02-43e8-8457-3b64eb7a9544

View File

@@ -0,0 +1,86 @@
<template>
<div :class="classes">
<div :class="headClasses" v-if="showHead"><slot name="title">
<p v-if="title">
<Icon v-if="icon" :type="icon"></Icon>
<span>{{title}}</span>
</p>
</slot></div>
<div :class="extraClasses" v-if="showExtra"><slot name="extra"></slot></div>
<div :class="bodyClasses" :style="bodyStyles"><slot></slot></div>
</div>
</template>
<script>
const prefixCls = 'ivu-card';
const defaultPadding = 16;
import Icon from '../icon/icon.vue';
export default {
name: 'Card',
components: { Icon },
props: {
bordered: {
type: Boolean,
default: true
},
disHover: {
type: Boolean,
default: false
},
shadow: {
type: Boolean,
default: false
},
padding: {
type: Number,
default: defaultPadding
},
title: {
type: String,
},
icon: {
type: String,
}
},
data () {
return {
showHead: true,
showExtra: true
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-bordered`]: this.bordered && !this.shadow,
[`${prefixCls}-dis-hover`]: this.disHover || this.shadow,
[`${prefixCls}-shadow`]: this.shadow
}
];
},
headClasses () {
return `${prefixCls}-head`;
},
extraClasses () {
return `${prefixCls}-extra`;
},
bodyClasses () {
return `${prefixCls}-body`;
},
bodyStyles () {
if (this.padding !== defaultPadding) {
return {
padding: `${this.padding}px`
};
} else {
return '';
}
}
},
mounted () {
this.showHead = this.title || this.$slots.title !== undefined;
this.showExtra = this.$slots.extra !== undefined;
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Card from './card.vue';
export default Card;

View File

@@ -0,0 +1 @@
d532e1ff-a0b7-4223-8921-4f3c5998d28a

View File

@@ -0,0 +1,3 @@
import CarouselItem from '../carousel/carousel-item.vue';
export default CarouselItem;

View File

@@ -0,0 +1 @@
79dff6f2-00af-4b76-8251-85bbe9df7576

View File

@@ -0,0 +1,50 @@
<template>
<div :class="prefixCls" :style="styles"><slot></slot></div>
</template>
<script>
const prefixCls = 'ivu-carousel-item';
export default {
componentName: 'carousel-item',
name: 'CarouselItem',
data () {
return {
prefixCls: prefixCls,
width: 0,
height: 'auto',
left: 0
};
},
computed: {
styles () {
return {
width: `${this.width}px`,
height: `${this.height}`,
left: `${this.left}px`
};
}
},
mounted () {
this.$parent.slotChange();
},
watch: {
width (val) {
if (val && this.$parent.loop) {
this.$nextTick(() => {
this.$parent.initCopyTrackDom();
});
}
},
height (val) {
if (val && this.$parent.loop) {
this.$nextTick(() => {
this.$parent.initCopyTrackDom();
});
}
}
},
beforeDestroy () {
this.$parent.slotChange();
}
};
</script>

View File

@@ -0,0 +1,336 @@
<template>
<div :class="classes">
<button type="button" :class="arrowClasses" class="left" @click="arrowEvent(-1)">
<Icon type="ios-arrow-back"></Icon>
</button>
<div :class="[prefixCls + '-list']">
<div :class="[prefixCls + '-track', showCopyTrack ? '' : 'higher']" :style="trackStyles" ref="originTrack" @click="handlerClickEvent('currentIndex')">
<slot></slot>
</div>
<div :class="[prefixCls + '-track', showCopyTrack ? 'higher' : '']" :style="copyTrackStyles" @click="handlerClickEvent('copyTrackIndex')" ref="copyTrack" v-if="loop">
</div>
</div>
<button type="button" :class="arrowClasses" class="right" @click="arrowEvent(1)">
<Icon type="ios-arrow-forward"></Icon>
</button>
<ul :class="dotsClasses">
<template v-for="n in slides.length">
<li :class="[n - 1 === currentIndex ? prefixCls + '-active' : '']"
@click="dotsEvent('click', n - 1)"
@mouseover="dotsEvent('hover', n - 1)">
<button type="button" :class="[radiusDot ? 'radius' : '']"></button>
</li>
</template>
</ul>
</div>
</template>
<script>
import Icon from '../icon/icon.vue';
import { getStyle, oneOf } from '../../utils/assist';
import { on, off } from '../../utils/dom';
const prefixCls = 'ivu-carousel';
export default {
name: 'Carousel',
components: { Icon },
props: {
arrow: {
type: String,
default: 'hover',
validator (value) {
return oneOf(value, ['hover', 'always', 'never']);
}
},
autoplay: {
type: Boolean,
default: false
},
autoplaySpeed: {
type: Number,
default: 2000
},
loop: {
type: Boolean,
default: false
},
easing: {
type: String,
default: 'ease'
},
dots: {
type: String,
default: 'inside',
validator (value) {
return oneOf(value, ['inside', 'outside', 'none']);
}
},
radiusDot: {
type: Boolean,
default: false
},
trigger: {
type: String,
default: 'click',
validator (value) {
return oneOf(value, ['click', 'hover']);
}
},
value: {
type: Number,
default: 0
},
height: {
type: [String, Number],
default: 'auto',
validator (value) {
return value === 'auto' || Object.prototype.toString.call(value) === '[object Number]';
}
}
},
data () {
return {
prefixCls: prefixCls,
listWidth: 0,
trackWidth: 0,
trackOffset: 0,
trackCopyOffset: 0,
showCopyTrack: false,
slides: [],
slideInstances: [],
timer: null,
ready: false,
currentIndex: this.value,
trackIndex: this.value,
copyTrackIndex: this.value,
hideTrackPos: -1, // 默认左滑
};
},
computed: {
classes () {
return [
`${prefixCls}`
];
},
trackStyles () {
// #6076
const visibleStyle = this.trackIndex === -1 ? 'hidden' : 'visible';
return {
width: `${this.trackWidth}px`,
transform: `translate3d(${-this.trackOffset}px, 0px, 0px)`,
transition: `transform 500ms ${this.easing}`,
visibility : visibleStyle
};
},
copyTrackStyles () {
return {
width: `${this.trackWidth}px`,
transform: `translate3d(${-this.trackCopyOffset}px, 0px, 0px)`,
transition: `transform 500ms ${this.easing}`,
position: 'absolute',
//top: 0
};
},
arrowClasses () {
return [
`${prefixCls}-arrow`,
`${prefixCls}-arrow-${this.arrow}`
];
},
dotsClasses () {
return [
`${prefixCls}-dots`,
`${prefixCls}-dots-${this.dots}`
];
}
},
methods: {
handlerClickEvent(type){
this.$emit('on-click',this[type]);
},
// find option component
findChild (cb) {
const find = function (child) {
const name = child.$options.componentName;
if (name) {
cb(child);
} else if (child.$children.length) {
child.$children.forEach((innerChild) => {
find(innerChild, cb);
});
}
};
if (this.slideInstances.length || !this.$children) {
this.slideInstances.forEach((child) => {
find(child);
});
} else {
this.$children.forEach((child) => {
find(child);
});
}
},
// copy trackDom
initCopyTrackDom () {
this.$nextTick(() => {
this.$refs.copyTrack.innerHTML = this.$refs.originTrack.innerHTML;
});
},
updateSlides (init) {
let slides = [];
let index = 1;
this.findChild((child) => {
slides.push({
$el: child.$el
});
child.index = index++;
if (init) {
this.slideInstances.push(child);
}
});
this.slides = slides;
this.updatePos();
},
updatePos () {
this.findChild((child) => {
child.width = this.listWidth;
child.height = typeof this.height === 'number' ? `${this.height}px` : this.height;
});
const slidesLength = this.slides.length || 0;
this.trackWidth = slidesLength * this.listWidth;
},
// use when slot changed
slotChange () {
this.$nextTick(() => {
this.slides = [];
this.slideInstances = [];
this.updateSlides(true, true);
this.updatePos();
this.updateOffset();
});
},
handleResize () {
this.listWidth = parseInt(getStyle(this.$el, 'width'));
this.updatePos();
this.updateOffset();
},
updateTrackPos (index) {
if (this.showCopyTrack) {
this.trackIndex = index;
} else {
this.copyTrackIndex = index;
}
},
updateTrackIndex (index) {
if (this.showCopyTrack) {
this.copyTrackIndex = index;
} else {
this.trackIndex = index;
}
this.currentIndex = index;
},
add (offset) {
// 获取单个轨道的图片数
let slidesLen = this.slides.length;
// 如果是无缝滚动,需要初始化双轨道位置
if (this.loop) {
if (offset > 0) {
// 初始化左滑轨道位置
this.hideTrackPos = -1;
} else {
// 初始化右滑轨道位置
this.hideTrackPos = slidesLen;
}
this.updateTrackPos(this.hideTrackPos);
}
// 获取当前展示图片的索引值
const oldIndex = this.showCopyTrack ? this.copyTrackIndex : this.trackIndex;
let index = oldIndex + offset;
while (index < 0) index += slidesLen;
if (((offset > 0 && index === slidesLen) || (offset < 0 && index === slidesLen - 1)) && this.loop) {
// 极限值(左滑:当前索引为总图片张数, 右滑:当前索引为总图片张数 - 1切换轨道
this.showCopyTrack = !this.showCopyTrack;
this.trackIndex += offset;
this.copyTrackIndex += offset;
} else {
if (!this.loop) index = index % this.slides.length;
this.updateTrackIndex(index);
}
this.currentIndex = index === this.slides.length ? 0 : index;
this.$emit('on-change', oldIndex, this.currentIndex);
this.$emit('input', this.currentIndex);
},
arrowEvent (offset) {
this.setAutoplay();
this.add(offset);
},
dotsEvent (event, n) {
let curIndex = this.showCopyTrack ? this.copyTrackIndex : this.trackIndex;
const oldCurrentIndex = this.currentIndex;
if (event === this.trigger && curIndex !== n) {
this.updateTrackIndex(n);
this.$emit('on-change', oldCurrentIndex, this.currentIndex);
this.$emit('input', n);
// Reset autoplay timer when trigger be activated
this.setAutoplay();
}
},
setAutoplay () {
window.clearInterval(this.timer);
if (this.autoplay) {
this.timer = window.setInterval(() => {
this.add(1);
}, this.autoplaySpeed);
}
},
updateOffset () {
this.$nextTick(() => {
/* hack: revise copyTrack offset (1px) */
let ofs = this.copyTrackIndex > 0 ? -1 : 1;
this.trackOffset = this.trackIndex * this.listWidth;
this.trackCopyOffset = this.copyTrackIndex * this.listWidth + ofs;
});
}
},
watch: {
autoplay () {
this.setAutoplay();
},
autoplaySpeed () {
this.setAutoplay();
},
trackIndex () {
this.updateOffset();
},
copyTrackIndex () {
this.updateOffset();
},
height () {
this.updatePos();
},
value (val) {
// this.currentIndex = val;
// this.trackIndex = val;
this.updateTrackIndex(val);
this.setAutoplay();
}
},
mounted () {
this.updateSlides(true);
this.handleResize();
this.setAutoplay();
// window.addEventListener('resize', this.handleResize, false);
on(window, 'resize', this.handleResize);
},
beforeDestroy () {
// window.removeEventListener('resize', this.handleResize, false);
off(window, 'resize', this.handleResize);
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Carousel from './carousel.vue';
import CarouselItem from './carousel-item.vue';
Carousel.Item = CarouselItem;
export default Carousel;

View File

@@ -0,0 +1 @@
837f5021-f1e7-4ba0-b23c-ed955d12c1cc

View File

@@ -0,0 +1,445 @@
<template>
<div :class="classes" v-click-outside="handleClose">
<div :class="[prefixCls + '-rel']" @click="toggleOpen" ref="reference">
<input type="hidden" :name="name" :value="currentValue">
<slot>
<i-input
:element-id="elementId"
ref="input"
:readonly="!filterable"
:disabled="disabled"
:value="displayInputRender"
@on-change="handleInput"
:size="size"
:placeholder="inputPlaceholder"></i-input>
<div
:class="[prefixCls + '-label']"
v-show="filterable && query === ''"
@click="handleFocus">{{ displayRender }}</div>
<Icon type="ios-close-circle" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSelect"></Icon>
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-arrow']"></Icon>
</slot>
</div>
<transition name="transition-drop">
<Drop
v-show="visible"
:class="{ [prefixCls + '-transfer']: transfer }"
ref="drop"
:data-transfer="transfer"
:transfer="transfer"
v-transfer-dom>
<div>
<Caspanel
v-show="!filterable || (filterable && query === '')"
ref="caspanel"
:prefix-cls="prefixCls"
:data="data"
:disabled="disabled"
:change-on-select="changeOnSelect"
:trigger="trigger"></Caspanel>
<div :class="[prefixCls + '-dropdown']" v-show="filterable && query !== '' && querySelections.length">
<ul :class="[selectPrefixCls + '-dropdown-list']">
<li
:class="[selectPrefixCls + '-item', {
[selectPrefixCls + '-item-disabled']: item.disabled
}]"
v-for="(item, index) in querySelections"
:key="index"
@click="handleSelectItem(index)" v-html="item.display"></li>
</ul>
</div>
<ul v-show="(filterable && query !== '' && !querySelections.length) || !data.length" :class="[prefixCls + '-not-found-tip']"><li>{{ localeNotFoundText }}</li></ul>
</div>
</Drop>
</transition>
</div>
</template>
<script>
import iInput from '../input/input.vue';
import Drop from '../select/dropdown.vue';
import Icon from '../icon/icon.vue';
import Caspanel from './caspanel.vue';
import {directive as clickOutside} from 'v-click-outside-x';
import TransferDom from '../../directives/transfer-dom';
import { oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import Locale from '../../mixins/locale';
const prefixCls = 'ivu-cascader';
const selectPrefixCls = 'ivu-select';
export default {
name: 'Cascader',
mixins: [ Emitter, Locale ],
components: { iInput, Drop, Icon, Caspanel },
directives: { clickOutside, TransferDom },
props: {
data: {
type: Array,
default () {
return [];
}
},
value: {
type: Array,
default () {
return [];
}
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: true
},
placeholder: {
type: String
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
trigger: {
validator (value) {
return oneOf(value, ['click', 'hover']);
},
default: 'click'
},
changeOnSelect: {
type: Boolean,
default: false
},
renderFormat: {
type: Function,
default (label) {
return label.join(' / ');
}
},
loadData: {
type: Function
},
filterable: {
type: Boolean,
default: false
},
notFoundText: {
type: String
},
transfer: {
type: Boolean,
default () {
return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
}
},
name: {
type: String
},
elementId: {
type: String
}
},
data () {
return {
prefixCls: prefixCls,
selectPrefixCls: selectPrefixCls,
visible: false,
selected: [],
tmpSelected: [],
updatingValue: false, // to fix set value in changeOnSelect type
currentValue: this.value,
query: '',
validDataStr: '',
isLoadedChildren: false // #950
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-show-clear`]: this.showCloseIcon,
[`${prefixCls}-size-${this.size}`]: !!this.size,
[`${prefixCls}-visible`]: this.visible,
[`${prefixCls}-disabled`]: this.disabled,
[`${prefixCls}-not-found`]: this.filterable && this.query !== '' && !this.querySelections.length
}
];
},
showCloseIcon () {
return this.currentValue && this.currentValue.length && this.clearable && !this.disabled;
},
displayRender () {
let label = [];
for (let i = 0; i < this.selected.length; i++) {
label.push(this.selected[i].label);
}
return this.renderFormat(label, this.selected);
},
displayInputRender () {
return this.filterable ? '' : this.displayRender;
},
localePlaceholder () {
if (this.placeholder === undefined) {
return this.t('i.select.placeholder');
} else {
return this.placeholder;
}
},
inputPlaceholder () {
return this.filterable && this.currentValue.length ? null : this.localePlaceholder;
},
localeNotFoundText () {
if (this.notFoundText === undefined) {
return this.t('i.select.noMatch');
} else {
return this.notFoundText;
}
},
querySelections () {
let selections = [];
function getSelections (arr, label, value) {
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
item.__label = label ? label + ' / ' + item.label : item.label;
item.__value = value ? [...value, item.value] : [item.value];
if (item.children && item.children.length) {
getSelections(item.children, item.__label, item.__value);
delete item.__label;
delete item.__value;
} else {
selections.push({
label: item.__label,
value: item.__value,
display: item.__label,
item: item,
disabled: !!item.disabled
});
}
}
}
getSelections(this.data);
selections = selections.filter(item => {
return item.label ? item.label.indexOf(this.query) > -1 : false;
}).map(item => {
item.display = item.display.replace(new RegExp(this.query, 'g'), `<span>${this.query}</span>`);
return item;
});
return selections;
},
// 3.4.0, global setting customArrow 有值时arrow 赋值空
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customArrow) {
type = '';
} else if (this.$IVIEW.cascader.arrow) {
type = this.$IVIEW.cascader.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customArrow) {
type = this.$IVIEW.cascader.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.arrowSize) {
size = this.$IVIEW.cascader.arrowSize;
}
}
return size;
}
},
methods: {
clearSelect () {
if (this.disabled) return false;
const oldVal = JSON.stringify(this.currentValue);
this.currentValue = this.selected = this.tmpSelected = [];
this.handleClose();
this.emitValue(this.currentValue, oldVal);
// this.$broadcast('on-clear');
this.broadcast('Caspanel', 'on-clear');
},
handleClose () {
this.visible = false;
},
toggleOpen () {
if (this.disabled) return false;
if (this.visible) {
if (!this.filterable) this.handleClose();
} else {
this.onFocus();
}
},
onFocus () {
this.visible = true;
if (!this.currentValue.length) {
this.broadcast('Caspanel', 'on-clear');
}
},
updateResult (result) {
this.tmpSelected = result;
},
updateSelected (init = false, changeOnSelectDataChange = false) {
// #2793 changeOnSelectDataChange used for changeOnSelect when data changed and set value
if (!this.changeOnSelect || init || changeOnSelectDataChange) {
this.broadcast('Caspanel', 'on-find-selected', {
value: this.currentValue
});
}
},
emitValue (val, oldVal) {
if (JSON.stringify(val) !== oldVal) {
this.$emit('on-change', this.currentValue, JSON.parse(JSON.stringify(this.selected)));
this.$nextTick(() => {
this.dispatch('FormItem', 'on-form-change', {
value: this.currentValue,
selected: JSON.parse(JSON.stringify(this.selected))
});
});
}
},
handleInput (event) {
this.query = event.target.value;
},
handleSelectItem (index) {
const item = this.querySelections[index];
if (item.item.disabled) return false;
this.query = '';
this.$refs.input.currentValue = '';
const oldVal = JSON.stringify(this.currentValue);
this.currentValue = item.value;
// use setTimeout for #4786, can not use nextTick, because @on-find-selected use nextTick
setTimeout(() => {
this.emitValue(this.currentValue, oldVal);
this.handleClose();
}, 0);
},
handleFocus () {
this.$refs.input.focus();
},
// 排除 loading 后的 data避免重复触发 updateSelect
getValidData (data) {
function deleteData (item) {
const new_item = Object.assign({}, item);
if ('loading' in new_item) {
delete new_item.loading;
}
if ('__value' in new_item) {
delete new_item.__value;
}
if ('__label' in new_item) {
delete new_item.__label;
}
if (Array.isArray(new_item.children) && new_item.children.length) {
new_item.children = new_item.children.map(i => deleteData(i));
}
return new_item;
}
return data.map(item => deleteData(item));
}
},
created () {
this.validDataStr = JSON.stringify(this.getValidData(this.data));
this.$on('on-result-change', (params) => {
// lastValue: is click the final val
// fromInit: is this emit from update value
const lastValue = params.lastValue;
const changeOnSelect = params.changeOnSelect;
const fromInit = params.fromInit;
if (lastValue || changeOnSelect) {
const oldVal = JSON.stringify(this.currentValue);
this.selected = this.tmpSelected;
let newVal = [];
this.selected.forEach((item) => {
newVal.push(item.value);
});
if (!fromInit) {
this.updatingValue = true;
this.currentValue = newVal;
this.emitValue(this.currentValue, oldVal);
}
}
if (lastValue && !fromInit) {
this.handleClose();
}
});
},
mounted () {
this.updateSelected(true);
},
watch: {
visible (val) {
if (val) {
if (this.currentValue.length) {
this.updateSelected();
}
if (this.transfer) {
this.$refs.drop.update();
}
this.broadcast('Drop', 'on-update-popper');
} else {
if (this.filterable) {
this.query = '';
this.$refs.input.currentValue = '';
}
if (this.transfer) {
this.$refs.drop.destroy();
}
this.broadcast('Drop', 'on-destroy-popper');
}
this.$emit('on-visible-change', val);
},
value (val) {
this.currentValue = val;
if (!val.length) this.selected = [];
},
currentValue () {
this.$emit('input', this.currentValue);
if (this.updatingValue) {
this.updatingValue = false;
return;
}
this.updateSelected(true);
},
data: {
deep: true,
handler () {
const validDataStr = JSON.stringify(this.getValidData(this.data));
if (validDataStr !== this.validDataStr) {
this.validDataStr = validDataStr;
if (!this.isLoadedChildren) {
this.$nextTick(() => this.updateSelected(false, this.changeOnSelect));
}
this.isLoadedChildren = false;
}
}
}
}
};
</script>

View File

@@ -0,0 +1,72 @@
<template>
<li :class="classes">
{{ data.label }}
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" v-if="showArrow" />
<i v-if="showLoading" class="ivu-icon ivu-icon-ios-loading ivu-load-loop ivu-cascader-menu-item-loading"></i>
</li>
</template>
<script>
import Icon from '../icon/icon.vue';
export default {
name: 'Casitem',
components: { Icon },
props: {
data: Object,
prefixCls: String,
tmpItem: Object
},
computed: {
classes () {
return [
`${this.prefixCls}-menu-item`,
{
[`${this.prefixCls}-menu-item-active`]: this.tmpItem.value === this.data.value,
[`${this.prefixCls}-menu-item-disabled`]: this.data.disabled
}
];
},
showArrow () {
return (this.data.children && this.data.children.length) || ('loading' in this.data && !this.data.loading);
},
showLoading () {
return 'loading' in this.data && this.data.loading;
},
// 3.4.0, global setting customArrow 有值时arrow 赋值空
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customItemArrow) {
type = '';
} else if (this.$IVIEW.cascader.itemArrow) {
type = this.$IVIEW.cascader.itemArrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.customItemArrow) {
type = this.$IVIEW.cascader.customItemArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cascader.itemArrowSize) {
size = this.$IVIEW.cascader.itemArrowSize;
}
}
return size;
}
}
};
</script>

View File

@@ -0,0 +1,192 @@
<template>
<span>
<ul v-if="data && data.length" :class="[prefixCls + '-menu']">
<Casitem
v-for="item in data"
:key="getKey()"
:prefix-cls="prefixCls"
:data="item"
:tmp-item="tmpItem"
@click.native.stop="handleClickItem(item, $event)"
@mouseenter.native.stop="handleHoverItem(item)"
></Casitem>
</ul>
<Caspanel
v-if="sublist && sublist.length"
:prefix-cls="prefixCls"
:data="sublist"
:disabled="disabled"
:trigger="trigger"
:change-on-select="changeOnSelect">
</Caspanel>
</span>
</template>
<script>
import Casitem from './casitem.vue';
import Emitter from '../../mixins/emitter';
import { findComponentUpward, findComponentDownward } from '../../utils/assist';
let key = 1;
export default {
name: 'Caspanel',
mixins: [ Emitter ],
components: { Casitem },
props: {
data: {
type: Array,
default () {
return [];
}
},
disabled: Boolean,
changeOnSelect: Boolean,
trigger: String,
prefixCls: String
},
data () {
return {
tmpItem: {},
result: [],
sublist: []
};
},
watch: {
data () {
this.sublist = [];
}
},
methods: {
isIcon(node){
let nodeName = (node.nodeName || '').toLocaleUpperCase();
let isIvu = node.classList.contains('ivu-icon');
if(nodeName == 'I' && isIvu){
return true;
}
return false;
},
handleClickItem (item, ev) {
let isIcon = this.isIcon(ev.target);
if (this.trigger !== 'click' && item.children && item.children.length) return; // #1922
this.handleTriggerItem(item, false, true,isIcon);
},
handleHoverItem (item) {
if (this.trigger !== 'hover' || !item.children || !item.children.length) return; // #1922
this.handleTriggerItem(item, false, true,false);
},
//#6158 -- default fromInit = false to fromInit = true;
handleTriggerItem (item, fromInit = true, fromUser = false,isIcon=false) {
if (item.disabled) return;
const cascader = findComponentUpward(this, 'Cascader');
if (item.loading !== undefined && !item.children.length) {
if (cascader && cascader.loadData) {
cascader.loadData(item, () => {
// todo
if (fromUser) {
cascader.isLoadedChildren = true;
}
if (item.children.length) {
this.handleTriggerItem(item);
}
});
return;
}
}
// return value back recursion // 向上递归,设置临时选中值(并非真实选中)
const backItem = this.getBaseItem(item);
// #5021 for this.changeOnSelect加 if 是因为 #4472
if (
this.changeOnSelect ||
(backItem.label !== this.tmpItem.label || backItem.value !== this.tmpItem.value) ||
(backItem.label === this.tmpItem.label && backItem.value === this.tmpItem.value)
) {
this.tmpItem = backItem;
this.emitUpdate([backItem]);
}
if (item.children && item.children.length){
this.sublist = item.children;
!isIcon && this.dispatch('Cascader', 'on-result-change', {
lastValue: false,
changeOnSelect: this.changeOnSelect,
fromInit: fromInit
});
// #1553
if (this.changeOnSelect) {
const Caspanel = findComponentDownward(this, 'Caspanel');
if (Caspanel) {
Caspanel.$emit('on-clear', true);
}
}
} else {
this.sublist = [];
!isIcon && this.dispatch('Cascader', 'on-result-change', {
lastValue: true,
changeOnSelect: this.changeOnSelect,
fromInit: fromInit
});
}
if (cascader) {
cascader.$refs.drop.update();
}
},
updateResult (item) {
this.result = [this.tmpItem].concat(item);
this.emitUpdate(this.result);
},
getBaseItem (item) {
let backItem = Object.assign({}, item);
if (backItem.children) {
delete backItem.children;
}
return backItem;
},
emitUpdate (result) {
if (this.$parent.$options.name === 'Caspanel') {
this.$parent.updateResult(result);
} else {
this.$parent.$parent.updateResult(result);
}
},
getKey () {
return key++;
}
},
mounted () {
this.$on('on-find-selected', (params) => {
const val = params.value;
let value = [...val];
for (let i = 0; i < value.length; i++) {
for (let j = 0; j < this.data.length; j++) {
if (value[i] === this.data[j].value) {
this.handleTriggerItem(this.data[j], true);
value.splice(0, 1);
this.$nextTick(() => {
this.broadcast('Caspanel', 'on-find-selected', {
value: value
});
});
return false;
}
}
}
});
// deep for #1553
this.$on('on-clear', (deep = false) => {
this.sublist = [];
this.tmpItem = {};
if (deep) {
const Caspanel = findComponentDownward(this, 'Caspanel');
if (Caspanel) {
Caspanel.$emit('on-clear', true);
}
}
});
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Cascader from './cascader.vue';
export default Cascader;

View File

@@ -0,0 +1 @@
1d7c928a-8e6d-4333-92c2-f87ddef538e0

View File

@@ -0,0 +1,2 @@
import CellGroup from '../cell/cell-group.vue';
export default CellGroup;

View File

@@ -0,0 +1 @@
dcc9deea-b148-49cc-a0c3-32f1e0817eed

View File

@@ -0,0 +1,20 @@
<template>
<div class="ivu-cell-group">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'CellGroup',
provide () {
return {
cellGroup: this
};
},
methods: {
handleClick (name) {
this.$emit('on-click', name);
}
}
};
</script>

View File

@@ -0,0 +1,32 @@
<template>
<div class="ivu-cell-item">
<div class="ivu-cell-icon">
<slot name="icon"></slot>
</div>
<div class="ivu-cell-main">
<div class="ivu-cell-title"><slot>{{ title }}</slot></div>
<div class="ivu-cell-label"><slot name="label">{{ label }}</slot></div>
</div>
<div class="ivu-cell-footer">
<span class="ivu-cell-extra"><slot name="extra">{{ extra }}</slot></span>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
},
label: {
type: String,
default: ''
},
extra: {
type: String,
default: ''
},
}
};
</script>

View File

@@ -0,0 +1,130 @@
<template>
<div :class="classes">
<a
v-if="to"
:href="linkUrl"
:target="target"
class="ivu-cell-link"
@click.exact="handleClickItem($event, false)"
@click.ctrl="handleClickItem($event, true)"
@click.meta="handleClickItem($event, true)">
<CellItem :title="title" :label="label" :extra="extra">
<slot name="icon" slot="icon"></slot>
<slot slot="default"></slot>
<slot name="extra" slot="extra"></slot>
<slot name="label" slot="label"></slot>
</CellItem>
</a>
<div class="ivu-cell-link" v-else @click="handleClickItem">
<CellItem :title="title" :label="label" :extra="extra">
<slot name="icon" slot="icon"></slot>
<slot slot="default"></slot>
<slot name="extra" slot="extra"></slot>
<slot name="label" slot="label"></slot>
</CellItem>
</div>
<div class="ivu-cell-arrow" v-if="to">
<slot name="arrow">
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" />
</slot>
</div>
</div>
</template>
<script>
import CellItem from './cell-item.vue';
import Icon from '../icon/icon.vue';
import mixinsLink from '../../mixins/link';
const prefixCls = 'ivu-cell';
export default {
name: 'Cell',
inject: ['cellGroup'],
mixins: [ mixinsLink ],
components: { CellItem, Icon },
props: {
name: {
type: [String, Number]
},
title: {
type: String,
default: ''
},
label: {
type: String,
default: ''
},
extra: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
selected: {
type: Boolean,
default: false
}
},
data () {
return {
prefixCls: prefixCls
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-disabled`]: this.disabled,
[`${prefixCls}-selected`]: this.selected,
[`${prefixCls}-with-link`]: this.to
}
];
},
// 3.4.0, global setting customArrow 有值时arrow 赋值空
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.cell.customArrow) {
type = '';
} else if (this.$IVIEW.cell.arrow) {
type = this.$IVIEW.cell.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.cell.customArrow) {
type = this.$IVIEW.cell.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.cell.arrowSize) {
size = this.$IVIEW.cell.arrowSize;
}
}
return size;
}
},
methods: {
handleClickItem (event, new_window) {
this.cellGroup.handleClick(this.name);
this.handleCheckClick(event, new_window);
}
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Cell from './cell.vue';
import CellGroup from './cell-group.vue';
Cell.Group = CellGroup;
export default Cell;

View File

@@ -0,0 +1 @@
f0f44445-398c-4d7e-b9a1-fddc01a999bc

View File

@@ -0,0 +1,3 @@
import CheckboxGroup from '../checkbox/checkbox-group.vue';
export default CheckboxGroup;

View File

@@ -0,0 +1 @@
fd70ab53-0ce3-490b-b5a9-8289f9090cf0

View File

@@ -0,0 +1,78 @@
<template>
<div :class="classes">
<slot></slot>
</div>
</template>
<script>
import { findComponentsDownward, oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
const prefixCls = 'ivu-checkbox-group';
export default {
name: 'CheckboxGroup',
mixins: [ Emitter ],
props: {
value: {
type: Array,
default () {
return [];
}
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
}
},
data () {
return {
currentValue: this.value,
childrens: []
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`ivu-checkbox-${this.size}`]: !!this.size
}
];
}
},
mounted () {
this.updateModel(true);
},
methods: {
updateModel (update) {
this.childrens = findComponentsDownward(this, 'Checkbox', 'CheckboxGroup');
if (this.childrens) {
const { value } = this;
this.childrens.forEach(child => {
child.model = value;
if (update) {
child.currentValue = value.indexOf(child.label) >= 0;
child.group = true;
}
});
}
},
change (data) {
this.currentValue = data;
this.$emit('input', data);
this.$emit('on-change', data);
this.dispatch('FormItem', 'on-form-change', data);
}
},
watch: {
value () {
this.updateModel(true);
}
}
};
</script>

View File

@@ -0,0 +1,171 @@
<template>
<label :class="wrapClasses">
<span :class="checkboxClasses">
<span :class="innerClasses"></span>
<input
v-if="group"
type="checkbox"
:class="inputClasses"
:disabled="disabled"
:value="label"
v-model="model"
:name="name"
@change="change"
@focus="onFocus"
@blur="onBlur">
<input
v-else
type="checkbox"
:class="inputClasses"
:disabled="disabled"
:checked="currentValue"
:name="name"
@change="change"
@focus="onFocus"
@blur="onBlur">
</span>
<slot><span v-if="showSlot">{{ label }}</span></slot>
</label>
</template>
<script>
import { findComponentUpward, oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
const prefixCls = 'ivu-checkbox';
export default {
name: 'Checkbox',
mixins: [ Emitter ],
props: {
disabled: {
type: Boolean,
default: false
},
value: {
type: [String, Number, Boolean],
default: false
},
trueValue: {
type: [String, Number, Boolean],
default: true
},
falseValue: {
type: [String, Number, Boolean],
default: false
},
label: {
type: [String, Number, Boolean]
},
indeterminate: {
type: Boolean,
default: false
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
name: {
type: String
}
},
data () {
return {
model: [],
currentValue: this.value,
group: false,
showSlot: true,
parent: findComponentUpward(this, 'CheckboxGroup'),
focusInner: false
};
},
computed: {
wrapClasses () {
return [
`${prefixCls}-wrapper`,
{
[`${prefixCls}-group-item`]: this.group,
[`${prefixCls}-wrapper-checked`]: this.currentValue,
[`${prefixCls}-wrapper-disabled`]: this.disabled,
[`${prefixCls}-${this.size}`]: !!this.size
}
];
},
checkboxClasses () {
return [
`${prefixCls}`,
{
[`${prefixCls}-checked`]: this.currentValue,
[`${prefixCls}-disabled`]: this.disabled,
[`${prefixCls}-indeterminate`]: this.indeterminate
}
];
},
innerClasses () {
return [
`${prefixCls}-inner`,
{
[`${prefixCls}-focus`]: this.focusInner
}
];
},
inputClasses () {
return `${prefixCls}-input`;
}
},
mounted () {
this.parent = findComponentUpward(this, 'CheckboxGroup');
if (this.parent) {
this.group = true;
}
if (this.group) {
this.parent.updateModel(true);
} else {
this.updateModel();
this.showSlot = this.$slots.default !== undefined;
}
},
methods: {
change (event) {
if (this.disabled) {
return false;
}
const checked = event.target.checked;
this.currentValue = checked;
const value = checked ? this.trueValue : this.falseValue;
this.$emit('input', value);
if (this.group) {
this.parent.change(this.model);
} else {
this.$emit('on-change', value);
this.dispatch('FormItem', 'on-form-change', value);
}
},
updateModel () {
this.currentValue = this.value === this.trueValue;
},
onBlur () {
this.focusInner = false;
},
onFocus () {
this.focusInner = true;
}
},
watch: {
value (val) {
if (val === this.trueValue || val === this.falseValue) {
this.updateModel();
} else {
throw 'Value should be trueValue or falseValue.';
}
}
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Checkbox from './checkbox.vue';
import CheckboxGroup from './checkbox-group.vue';
Checkbox.Group = CheckboxGroup;
export default Checkbox;

View File

@@ -0,0 +1 @@
6d840b63-c5cb-4b63-83c8-e86492a99e51

View File

@@ -0,0 +1,118 @@
<template>
<div :style="circleSize" :class="wrapClasses">
<svg viewBox="0 0 100 100">
<path :d="pathString" :stroke="trailColor" :stroke-width="trailWidth" :fill-opacity="0" :style="trailStyle" />
<path :d="pathString" :stroke-linecap="strokeLinecap" :stroke="strokeColor" :stroke-width="computedStrokeWidth" fill-opacity="0" :style="pathStyle" />
</svg>
<div :class="innerClasses">
<slot></slot>
</div>
</div>
</template>
<script>
import { oneOf } from '../../utils/assist';
const prefixCls = 'ivu-chart-circle';
export default {
name: 'iCircle',
props: {
percent: {
type: Number,
default: 0
},
size: {
type: Number,
default: 120
},
strokeWidth: {
type: Number,
default: 6
},
strokeColor: {
type: String,
default: '#2d8cf0'
},
strokeLinecap: {
validator (value) {
return oneOf(value, ['square', 'round']);
},
default: 'round'
},
trailWidth: {
type: Number,
default: 5
},
trailColor: {
type: String,
default: '#eaeef2'
},
dashboard: {
type: Boolean,
default: false
}
},
computed: {
circleSize () {
return {
width: `${this.size}px`,
height: `${this.size}px`
};
},
computedStrokeWidth () {
return this.percent === 0 && this.dashboard ? 0 : this.strokeWidth;
},
radius () {
return 50 - this.strokeWidth / 2;
},
pathString () {
if (this.dashboard) {
return `M 50,50 m 0,${this.radius}
a ${this.radius},${this.radius} 0 1 1 0,-${2 * this.radius}
a ${this.radius},${this.radius} 0 1 1 0,${2 * this.radius}`;
} else {
return `M 50,50 m 0,-${this.radius}
a ${this.radius},${this.radius} 0 1 1 0,${2 * this.radius}
a ${this.radius},${this.radius} 0 1 1 0,-${2 * this.radius}`;
}
},
len () {
return Math.PI * 2 * this.radius;
},
trailStyle () {
let style = {};
if (this.dashboard) {
style = {
'stroke-dasharray': `${this.len - 75}px ${this.len}px`,
'stroke-dashoffset': `-${75 / 2}px`,
'transition': 'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s'
};
}
return style;
},
pathStyle () {
let style = {};
if (this.dashboard) {
style = {
'stroke-dasharray': `${(this.percent / 100) * (this.len - 75)}px ${this.len}px`,
'stroke-dashoffset': `-${75 / 2}px`,
'transition': 'stroke-dashoffset .3s ease 0s, stroke-dasharray .6s ease 0s, stroke .6s, stroke-width .06s ease .6s'
};
} else {
style = {
'stroke-dasharray': `${this.len}px ${this.len}px`,
'stroke-dashoffset': `${((100 - this.percent) / 100 * this.len)}px`,
'transition': 'stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease'
};
}
return style;
},
wrapClasses () {
return `${prefixCls}`;
},
innerClasses () {
return `${prefixCls}-inner`;
}
}
};
</script>

View File

@@ -0,0 +1,2 @@
import Circle from './circle.vue';
export default Circle;

View File

@@ -0,0 +1 @@
2b4913cf-5569-4059-a860-2048d1518fea

View File

@@ -0,0 +1,3 @@
import Col from '../grid/col.vue';
export default Col;

View File

@@ -0,0 +1 @@
495ba017-02d6-4659-93a1-d0e1fc19bb27

View File

@@ -0,0 +1,111 @@
<template>
<div :class="classes">
<slot></slot>
</div>
</template>
<script>
const prefixCls = 'ivu-collapse';
export default {
name: 'Collapse',
props: {
accordion: {
type: Boolean,
default: false
},
value: {
type: [Array, String]
},
simple: {
type: Boolean,
default: false
}
},
data () {
return {
currentValue: this.value
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-simple`]: this.simple
}
];
}
},
mounted () {
this.setActive();
},
methods: {
setActive () {
const activeKey = this.getActiveKey();
this.$nextTick(() => {
this.$children.forEach((child, index) => {
const name = child.name || index.toString();
child.isActive = activeKey.indexOf(name) > -1;
child.index = index;
});
});
},
getActiveKey () {
let activeKey = this.currentValue || [];
const accordion = this.accordion;
if (!Array.isArray(activeKey)) {
activeKey = [activeKey];
}
if (accordion && activeKey.length > 1) {
activeKey = [activeKey[0]];
}
for (let i = 0; i < activeKey.length; i++) {
activeKey[i] = activeKey[i].toString();
}
return activeKey;
},
toggle (data) {
const name = data.name.toString();
let newActiveKey = [];
if (this.accordion) {
if (!data.isActive) {
newActiveKey.push(name);
}
} else {
let activeKey = this.getActiveKey();
const nameIndex = activeKey.indexOf(name);
if (data.isActive) {
if (nameIndex > -1) {
activeKey.splice(nameIndex, 1);
}
} else {
if (nameIndex < 0) {
activeKey.push(name);
}
}
newActiveKey = activeKey;
}
this.currentValue = newActiveKey;
this.$emit('input', newActiveKey);
this.$emit('on-change', newActiveKey);
}
},
watch: {
value (val) {
this.currentValue = val;
},
currentValue () {
this.setActive();
}
}
};
</script>

View File

@@ -0,0 +1,5 @@
import Collapse from './collapse.vue';
import Panel from './panel.vue';
Collapse.Panel = Panel;
export default Collapse;

View File

@@ -0,0 +1,69 @@
<template>
<div :class="itemClasses">
<div :class="headerClasses" @click="toggle">
<Icon type="ios-arrow-forward" v-if="!hideArrow"></Icon>
<slot></slot>
</div>
<collapse-transition v-if="mounted">
<div :class="contentClasses" v-show="isActive">
<div :class="boxClasses"><slot name="content"></slot></div>
</div>
</collapse-transition>
</div>
</template>
<script>
import Icon from '../icon/icon.vue';
import CollapseTransition from '../base/collapse-transition';
const prefixCls = 'ivu-collapse';
export default {
name: 'Panel',
components: { Icon, CollapseTransition },
props: {
name: {
type: String
},
hideArrow: {
type: Boolean,
default: false
}
},
data () {
return {
index: 0, // use index for default when name is null
isActive: false,
mounted: false
};
},
computed: {
itemClasses () {
return [
`${prefixCls}-item`,
{
[`${prefixCls}-item-active`]: this.isActive
}
];
},
headerClasses () {
return `${prefixCls}-header`;
},
contentClasses () {
return `${prefixCls}-content`;
},
boxClasses () {
return `${prefixCls}-content-box`;
}
},
methods: {
toggle () {
this.$parent.toggle({
name: this.name || this.index,
isActive: this.isActive
});
}
},
mounted () {
this.mounted = true;
}
};
</script>

View File

@@ -0,0 +1 @@
8f220339-6d43-4b19-be87-3032e0bd7c72

View File

@@ -0,0 +1,103 @@
<template>
<div
:class="[prefixCls + '-alpha']"
tabindex="0"
@click="$el.focus()"
@keydown.esc="handleEscape"
@keydown.left="handleLeft"
@keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div :class="[prefixCls + '-alpha-checkboard-wrap']">
<div :class="[prefixCls + '-alpha-checkerboard']"></div>
</div>
<div
:style="gradientStyle"
:class="[prefixCls + '-alpha-gradient']"></div>
<div
ref="container"
:class="[prefixCls + '-alpha-container']"
@mousedown="handleMouseDown"
@touchmove="handleChange"
@touchstart="handleChange">
<div
:style="{top: 0, left: `${value.a * 100}%`}"
:class="[prefixCls + '-alpha-pointer']">
<div :class="[prefixCls + '-alpha-picker']"></div>
</div>
</div>
</div>
</template>
<script>
import HSAMixin from './hsaMixin';
import Prefixes from './prefixMixin';
import {clamp, toRGBAString} from './utils';
export default {
name: 'Alpha',
mixins: [HSAMixin, Prefixes],
data() {
const normalStep = 1;
const jumpStep = 10;
return {
left: -normalStep,
right: normalStep,
up: jumpStep,
down: -jumpStep,
powerKey: 'shiftKey',
};
},
computed: {
gradientStyle() {
const {r, g, b} = this.value.rgba;
const start = toRGBAString({r, g, b, a: 0});
const finish = toRGBAString({r, g, b, a: 1});
return {background: `linear-gradient(to right, ${start} 0%, ${finish} 100%)`};
},
},
methods: {
change(newAlpha) {
const {h, s, l} = this.value.hsl;
const {a} = this.value;
if (a !== newAlpha) {
this.$emit('change', {h, s, l, a: newAlpha, source: 'rgba'});
}
},
handleSlide(e, direction) {
e.preventDefault();
e.stopPropagation();
this.change(clamp(e[this.powerKey] ? direction : Math.round(this.value.hsl.a * 100 + direction) / 100, 0, 1));
},
handleChange(e) {
e.preventDefault();
e.stopPropagation();
const left = this.getLeft(e);
if (left < 0) {
this.change(0);
return;
}
const {clientWidth} = this.$refs.container;
if (left > clientWidth) {
this.change(1);
return;
}
this.change(Math.round(left * 100 / clientWidth) / 100);
},
},
};
</script>

View File

@@ -0,0 +1,512 @@
<template>
<div
v-click-outside="handleClose"
:class="classes">
<div
ref="reference"
:class="wrapClasses"
@click="toggleVisible">
<input
:name="name"
:value="currentValue"
type="hidden">
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="arrowClasses"></Icon>
<div
ref="input"
:tabindex="disabled ? undefined : 0"
:class="inputClasses"
@keydown.tab="onTab"
@keydown.esc="onEscape"
@keydown.up="onArrow"
@keydown.down="onArrow"
>
<div :class="[prefixCls + '-color']">
<div
v-show="value === '' && !visible"
:class="[prefixCls + '-color-empty']">
<i :class="[iconPrefixCls, iconPrefixCls + '-ios-close']"></i>
</div>
<div
v-show="value || visible"
:style="displayedColorStyle"></div>
</div>
</div>
</div>
<transition name="transition-drop">
<Drop
v-transfer-dom
v-show="visible"
ref="drop"
:placement="placement"
:data-transfer="transfer"
:transfer="transfer"
:class="dropClasses"
>
<transition name="fade">
<div
v-if="visible"
:class="[prefixCls + '-picker']">
<div :class="[prefixCls + '-picker-wrapper']">
<div :class="[prefixCls + '-picker-panel']">
<Saturation
ref="saturation"
v-model="saturationColors"
:focused="visible"
@change="childChange"
@keydown.native.tab="handleFirstTab"
></Saturation>
</div>
<div
v-if="hue"
:class="[prefixCls + '-picker-hue-slider']">
<Hue
v-model="saturationColors"
@change="childChange"></Hue>
</div>
<div
v-if="alpha"
:class="[prefixCls + '-picker-alpha-slider']">
<Alpha
v-model="saturationColors"
@change="childChange"></Alpha>
</div>
<recommend-colors
v-if="colors.length"
:list="colors"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
<recommend-colors
v-if="!colors.length && recommend"
:list="recommendedColor"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
</div>
<div :class="[prefixCls + '-confirm']">
<span :class="confirmColorClasses">
<template v-if="editable">
<i-input :value="formatColor" size="small" @on-enter="handleEditColor" @on-blur="handleEditColor"></i-input>
</template>
<template v-else>{{formatColor}}</template>
</span>
<i-button
ref="clear"
:tabindex="0"
size="small"
@click.native="handleClear"
@keydown.enter="handleClear"
@keydown.native.esc="closer"
>{{t('i.datepicker.clear')}}</i-button>
<i-button
ref="ok"
:tabindex="0"
size="small"
type="primary"
@click.native="handleSuccess"
@keydown.native.tab="handleLastTab"
@keydown.enter="handleSuccess"
@keydown.native.esc="closer"
>{{t('i.datepicker.ok')}}</i-button>
</div>
</div>
</transition>
</Drop>
</transition>
</div>
</template>
<script>
import tinycolor from 'tinycolor2';
import {directive as clickOutside} from 'v-click-outside-x';
import TransferDom from '../../directives/transfer-dom';
import Drop from '../../components/select/dropdown.vue';
import RecommendColors from './recommend-colors.vue';
import Saturation from './saturation.vue';
import Hue from './hue.vue';
import Alpha from './alpha.vue';
import iInput from '../input/input.vue';
import iButton from '../button/button.vue';
import Icon from '../icon/icon.vue';
import Locale from '../../mixins/locale';
import {oneOf} from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import Prefixes from './prefixMixin';
import {changeColor, toRGBAString} from './utils';
export default {
name: 'ColorPicker',
components: {Drop, RecommendColors, Saturation, Hue, Alpha, iInput, iButton, Icon},
directives: {clickOutside, TransferDom},
mixins: [Emitter, Locale, Prefixes],
props: {
value: {
type: String,
default: undefined,
},
hue: {
type: Boolean,
default: true,
},
alpha: {
type: Boolean,
default: false,
},
recommend: {
type: Boolean,
default: false,
},
format: {
type: String,
validator(value) {
return oneOf(value, ['hsl', 'hsv', 'hex', 'rgb']);
},
default: undefined,
},
colors: {
type: Array,
default() {
return [];
},
},
disabled: {
type: Boolean,
default: false,
},
size: {
validator(value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
hideDropDown: {
type: Boolean,
default: false,
},
placement: {
type: String,
validator(value) {
return oneOf(value, [
'top',
'top-start',
'top-end',
'bottom',
'bottom-start',
'bottom-end',
'left',
'left-start',
'left-end',
'right',
'right-start',
'right-end',
]);
},
default: 'bottom',
},
transfer: {
type: Boolean,
default () {
return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
}
},
name: {
type: String,
default: undefined,
},
editable: {
type: Boolean,
default: true
},
},
data() {
return {
val: changeColor(this.value),
currentValue: this.value,
dragging: false,
visible: false,
recommendedColor: [
'#2d8cf0',
'#19be6b',
'#ff9900',
'#ed4014',
'#00b5ff',
'#19c919',
'#f9e31c',
'#ea1a1a',
'#9b1dea',
'#00c2b1',
'#ac7a33',
'#1d35ea',
'#8bc34a',
'#f16b62',
'#ea4ca3',
'#0d94aa',
'#febd79',
'#5d4037',
'#00bcd4',
'#f06292',
'#cddc39',
'#607d8b',
'#000000',
'#ffffff',
],
};
},
computed: {
arrowClasses() {
return [
`${this.inputPrefixCls}-icon`,
`${this.inputPrefixCls}-icon-normal`,
];
},
transition() {
return oneOf(this.placement, ['bottom-start', 'bottom', 'bottom-end']) ? 'slide-up' : 'fade';
},
saturationColors: {
get() {
return this.val;
},
set(newVal) {
this.val = newVal;
this.$emit('on-active-change', this.formatColor);
},
},
classes() {
return [
`${this.prefixCls}`,
{
[`${this.prefixCls}-transfer`]: this.transfer,
},
];
},
wrapClasses() {
return [
`${this.prefixCls}-rel`,
`${this.prefixCls}-${this.size}`,
`${this.inputPrefixCls}-wrapper`,
`${this.inputPrefixCls}-wrapper-${this.size}`,
{
[`${this.prefixCls}-disabled`]: this.disabled,
},
];
},
inputClasses() {
return [
`${this.prefixCls}-input`,
`${this.inputPrefixCls}`,
`${this.inputPrefixCls}-${this.size}`,
{
[`${this.prefixCls}-focused`]: this.visible,
[`${this.prefixCls}-disabled`]: this.disabled,
},
];
},
dropClasses() {
return [
`${this.transferPrefixCls}-no-max-height`,
{
[`${this.prefixCls}-transfer`]: this.transfer,
[`${this.prefixCls}-hide-drop`]: this.hideDropDown,
},
];
},
displayedColorStyle() {
return {backgroundColor: toRGBAString(this.visible ? this.saturationColors.rgba : tinycolor(this.value).toRgb())};
},
formatColor() {
const {format, saturationColors} = this;
if (format) {
if (format === 'hsl') {
return tinycolor(saturationColors.hsl).toHslString();
}
if (format === 'hsv') {
return tinycolor(saturationColors.hsv).toHsvString();
}
if (format === 'hex') {
return saturationColors.hex;
}
if (format === 'rgb') {
return toRGBAString(saturationColors.rgba);
}
} else if (this.alpha) {
return toRGBAString(saturationColors.rgba);
}
return saturationColors.hex;
},
confirmColorClasses () {
return [
`${this.prefixCls}-confirm-color`,
{
[`${this.prefixCls}-confirm-color-editable`]: this.editable
}
];
},
// 3.4.0, global setting customArrow 有值时arrow 赋值空
arrowType () {
let type = 'ios-arrow-down';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.customArrow) {
type = '';
} else if (this.$IVIEW.colorPicker.arrow) {
type = this.$IVIEW.colorPicker.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.customArrow) {
type = this.$IVIEW.colorPicker.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.colorPicker.arrowSize) {
size = this.$IVIEW.colorPicker.arrowSize;
}
}
return size;
}
},
watch: {
value(newVal) {
this.val = changeColor(newVal);
},
visible(val) {
this.val = changeColor(this.value);
this.$refs.drop[val ? 'update' : 'destroy']();
this.$emit('on-open-change', Boolean(val));
},
},
mounted() {
this.$on('on-escape-keydown', this.closer);
this.$on('on-dragging', this.setDragging);
},
methods: {
setDragging(value) {
this.dragging = value;
},
handleClose(event) {
if (this.visible) {
if (this.dragging || event.type === 'mousedown') {
event.preventDefault();
return;
}
if (this.transfer) {
const {$el} = this.$refs.drop;
if ($el === event.target || $el.contains(event.target)) {
return;
}
}
this.closer(event);
return;
}
this.visible = false;
},
toggleVisible() {
if (this.disabled) {
return;
}
this.visible = !this.visible;
this.$refs.input.focus();
},
childChange(data) {
this.colorChange(data);
},
colorChange(data, oldHue) {
this.oldHue = this.saturationColors.hsl.h;
this.saturationColors = changeColor(data, oldHue || this.oldHue);
},
closer(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
this.visible = false;
this.$refs.input.focus();
},
handleButtons(event, value) {
this.currentValue = value;
this.$emit('input', value);
this.$emit('on-change', value);
this.dispatch('FormItem', 'on-form-change', value);
this.closer(event);
},
handleSuccess(event) {
this.handleButtons(event, this.formatColor);
this.$emit('on-pick-success');
},
handleClear(event) {
this.handleButtons(event, '');
this.$emit('on-pick-clear');
},
handleSelectColor(color) {
this.val = changeColor(color);
this.$emit('on-active-change', this.formatColor);
},
handleEditColor (event) {
const value = event.target.value;
this.handleSelectColor(value);
},
handleFirstTab(event) {
if (event.shiftKey) {
event.preventDefault();
event.stopPropagation();
this.$refs.ok.$el.focus();
}
},
handleLastTab(event) {
if (!event.shiftKey) {
event.preventDefault();
event.stopPropagation();
this.$refs.saturation.$el.focus();
}
},
onTab(event) {
if (this.visible) {
event.preventDefault();
}
},
onEscape(event) {
if (this.visible) {
this.closer(event);
}
},
onArrow(event) {
if (!this.visible) {
event.preventDefault();
event.stopPropagation();
this.visible = true;
}
},
},
};
</script>

View File

@@ -0,0 +1,7 @@
export default {
methods: {
handleEscape(e) {
this.dispatch('ColorPicker', 'on-escape-keydown', e);
},
},
};

View File

@@ -0,0 +1,78 @@
import Emitter from '../../mixins/emitter';
import handleEscapeMixin from './handleEscapeMixin';
import {getTouches} from './utils';
import { on, off } from '../../utils/dom';
export default {
mixins: [Emitter, handleEscapeMixin],
props: {
focused: {
type: Boolean,
default: false,
},
value: {
type: Object,
default: undefined,
},
},
beforeDestroy() {
this.unbindEventListeners();
},
created() {
if (this.focused) {
setTimeout(() => this.$el.focus(), 1);
}
},
methods: {
handleLeft(e) {
this.handleSlide(e, this.left, 'left');
},
handleRight(e) {
this.handleSlide(e, this.right, 'right');
},
handleUp(e) {
this.handleSlide(e, this.up, 'up');
},
handleDown(e) {
this.handleSlide(e, this.down, 'down');
},
handleMouseDown(e) {
this.dispatch('ColorPicker', 'on-dragging', true);
this.handleChange(e, true);
// window.addEventListener('mousemove', this.handleChange, false);
// window.addEventListener('mouseup', this.handleMouseUp, false);
on(window, 'mousemove', this.handleChange);
on(window, 'mouseup', this.handleMouseUp);
},
handleMouseUp() {
this.unbindEventListeners();
},
unbindEventListeners() {
// window.removeEventListener('mousemove', this.handleChange);
// window.removeEventListener('mouseup', this.handleMouseUp);
off(window, 'mousemove', this.handleChange);
off(window, 'mouseup', this.handleMouseUp);
// This timeout is required so that the click handler for click-outside
// has the chance to run before the mouseup removes the dragging flag.
setTimeout(() => this.dispatch('ColorPicker', 'on-dragging', false), 1);
},
getLeft(e) {
const {container} = this.$refs;
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
const pageX = e.pageX || getTouches(e, 'PageX');
return pageX - xOffset;
},
getTop(e) {
const {container} = this.$refs;
const yOffset = container.getBoundingClientRect().top + window.pageYOffset;
const pageY = e.pageY || getTouches(e, 'PageY');
return pageY - yOffset;
},
},
};

View File

@@ -0,0 +1,101 @@
<template>
<div
:class="[prefixCls + '-hue']"
tabindex="0"
@click="$el.focus()"
@keydown.esc="handleEscape"
@keydown.left="handleLeft"
@keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div
ref="container"
:class="[prefixCls + '-hue-container']"
@mousedown="handleMouseDown"
@touchmove="handleChange"
@touchstart="handleChange">
<div
:style="{top: 0, left: `${percent}%`}"
:class="[prefixCls + '-hue-pointer']">
<div :class="[prefixCls + '-hue-picker']"></div>
</div>
</div>
</div>
</template>
<script>
import HASMixin from './hsaMixin';
import Prefixes from './prefixMixin';
import {clamp} from './utils';
export default {
name: 'Hue',
mixins: [HASMixin, Prefixes],
data() {
const normalStep = 1 / 360 * 25;
const jumpStep = 20 * normalStep;
return {
left: -normalStep,
right: normalStep,
up: jumpStep,
down: -jumpStep,
powerKey: 'shiftKey',
percent: clamp(this.value.hsl.h * 100 / 360, 0, 100),
};
},
watch: {
value () {
this.percent = clamp(this.value.hsl.h * 100 / 360, 0, 100);
}
},
methods: {
change(percent) {
this.percent = clamp(percent, 0, 100);
const {h, s, l, a} = this.value.hsl;
const newHue = clamp(percent / 100 * 360, 0, 360);
if (h !== newHue) {
this.$emit('change', {h: newHue, s, l, a, source: 'hsl'});
}
},
handleSlide(e, direction) {
e.preventDefault();
e.stopPropagation();
if (e[this.powerKey]) {
this.change(direction < 0 ? 0 : 100);
return;
}
this.change(this.percent + direction);
},
handleChange(e) {
e.preventDefault();
e.stopPropagation();
const left = this.getLeft(e);
if (left < 0) {
this.change(0);
return;
}
const {clientWidth} = this.$refs.container;
if (left > clientWidth) {
this.change(100);
return;
}
this.change(left * 100 / clientWidth);
},
},
};
</script>

View File

@@ -0,0 +1,3 @@
import ColorPicker from './color-picker.vue';
export default ColorPicker;

View File

@@ -0,0 +1,10 @@
export default {
data() {
return {
prefixCls: 'ivu-color-picker',
inputPrefixCls: 'ivu-input',
iconPrefixCls: 'ivu-icon',
transferPrefixCls: 'ivu-transfer',
};
},
};

View File

@@ -0,0 +1,153 @@
<template>
<div
ref="reference"
tabindex="0"
@click="handleClick"
@keydown.esc="handleEscape"
@keydown.enter="handleEnter"
@keydown.left="handleArrow($event, 'x', left)"
@keydown.right="handleArrow($event, 'x', right)"
@keydown.up="handleArrow($event, 'y', up)"
@keydown.down="handleArrow($event, 'y', down)"
@blur="blurColor"
@focus="focusColor"
>
<template v-for="(item, index) in list">
<div
:key="item + ':' + index"
:class="[prefixCls + '-picker-colors-wrapper']">
<div :data-color-id="index">
<div
:style="{background: item}"
:class="[prefixCls + '-picker-colors-wrapper-color']"
></div>
<div
:ref="'color-circle-' + index"
:class="[prefixCls + '-picker-colors-wrapper-circle', hideClass]"></div>
</div>
</div>
<br v-if="lineBreak(list, index)">
</template>
</div>
</template>
<script>
import Emitter from '../../mixins/emitter';
import HandleEscapeMixin from './handleEscapeMixin';
import Prefixes from './prefixMixin';
import {clamp} from './utils';
export default {
name: 'RecommendedColors',
mixins: [Emitter, HandleEscapeMixin, Prefixes],
props: {
list: {
type: Array,
default: undefined,
},
},
data() {
const columns = 12;
const rows = Math.ceil(this.list.length / columns);
const normalStep = 1;
return {
left: -normalStep,
right: normalStep,
up: -normalStep,
down: normalStep,
powerKey: 'shiftKey',
grid: {x: 1, y: 1},
rows,
columns,
};
},
computed: {
hideClass() {
return `${this.prefixCls}-hide`;
},
linearIndex() {
return this.getLinearIndex(this.grid);
},
currentCircle() {
return this.$refs[`color-circle-${this.linearIndex}`][0];
},
},
methods: {
getLinearIndex(grid) {
return this.columns * (grid.y - 1) + grid.x - 1;
},
getMaxLimit(axis) {
return axis === 'x' ? this.columns : this.rows;
},
handleArrow(e, axis, direction) {
e.preventDefault();
e.stopPropagation();
this.blurColor();
const grid = {...this.grid};
if (e[this.powerKey]) {
if (direction < 0) {
grid[axis] = 1;
} else {
grid[axis] = this.getMaxLimit(axis);
}
} else {
grid[axis] += direction;
}
const index = this.getLinearIndex(grid);
if (index >= 0 && index < this.list.length) {
this.grid[axis] = clamp(grid[axis], 1, this.getMaxLimit(axis));
}
this.focusColor();
},
blurColor() {
this.currentCircle.classList.add(this.hideClass);
},
focusColor() {
this.currentCircle.classList.remove(this.hideClass);
},
handleEnter(e) {
this.handleClick(e, this.currentCircle);
},
handleClick(e, circle) {
e.preventDefault();
e.stopPropagation();
this.$refs.reference.focus();
const target = circle || e.target;
const colorId = target.dataset.colorId || target.parentElement.dataset.colorId;
if (colorId) {
this.blurColor();
const id = Number(colorId) + 1;
this.grid.x = id % this.columns || this.columns;
this.grid.y = Math.ceil(id / this.columns);
this.focusColor();
this.$emit('picker-color', this.list[colorId]);
this.$emit('change', {hex: this.list[colorId], source: 'hex'});
}
},
lineBreak(list, index) {
if (!index) {
return false;
}
const nextIndex = index + 1;
return nextIndex < list.length && nextIndex % this.columns === 0;
},
},
};
</script>

View File

@@ -0,0 +1,101 @@
<template>
<div
:class="[prefixCls + '-saturation-wrapper']"
tabindex="0"
@keydown.esc="handleEscape"
@click="$el.focus()"
@keydown.left="handleLeft"
@keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div
ref="container"
:style="bgColorStyle"
:class="[prefixCls + '-saturation']"
@mousedown="handleMouseDown">
<div :class="[prefixCls + '-saturation--white']"></div>
<div :class="[prefixCls + '-saturation--black']"></div>
<div
:style="pointerStyle"
:class="[prefixCls + '-saturation-pointer']">
<div :class="[prefixCls + '-saturation-circle']"></div>
</div>
</div>
</div>
</template>
<script>
import HSAMixin from './hsaMixin';
import Prefixes from './prefixMixin';
import {clamp, getIncrement} from './utils';
import { on, off } from '../../utils/dom';
export default {
name: 'Saturation',
mixins: [HSAMixin, Prefixes],
data() {
const normalStep = 0.01;
return {
left: -normalStep,
right: normalStep,
up: normalStep,
down: -normalStep,
multiplier: 10,
powerKey: 'shiftKey',
};
},
computed: {
bgColorStyle() {
return {background: `hsl(${this.value.hsv.h}, 100%, 50%)`};
},
pointerStyle() {
return {top: `${-(this.value.hsv.v * 100) + 1 + 100}%`, left: `${this.value.hsv.s * 100}%`};
},
},
methods: {
change(h, s, v, a) {
this.$emit('change', {h, s, v, a, source: 'hsva'});
},
handleSlide(e, direction, key) {
e.preventDefault();
e.stopPropagation();
const isPowerKey = e[this.powerKey];
const increment = isPowerKey ? direction * this.multiplier : direction;
const {h, s, v, a} = this.value.hsv;
const saturation = clamp(s + getIncrement(key, ['left', 'right'], increment), 0, 1);
const bright = clamp(v + getIncrement(key, ['up', 'down'], increment), 0, 1);
this.change(h, saturation, bright, a);
},
handleChange(e) {
e.preventDefault();
e.stopPropagation();
const {clientWidth, clientHeight} = this.$refs.container;
const left = clamp(this.getLeft(e), 0, clientWidth);
const top = clamp(this.getTop(e), 0, clientHeight);
const saturation = left / clientWidth;
const bright = clamp(1 - top / clientHeight, 0, 1);
this.change(this.value.hsv.h, saturation, bright, this.value.hsv.a);
},
handleMouseDown(e) {
HSAMixin.methods.handleMouseDown.call(this, e);
// window.addEventListener('mouseup', this.handleChange, false);
on(window, 'mouseup', this.handleChange);
},
unbindEventListeners(e) {
HSAMixin.methods.unbindEventListeners.call(this, e);
// window.removeEventListener('mouseup', this.handleChange);
off(window, 'mouseup', this.handleChange);
},
},
};
</script>

View File

@@ -0,0 +1,118 @@
import tinycolor from 'tinycolor2';
import {oneOf} from '../../utils/assist';
function setAlpha(data, alpha) {
const color = tinycolor(data);
const {_a} = color;
if (_a === undefined || _a === null) {
color.setAlpha(alpha || 1);
}
return color;
}
function getColor(data, colorData) {
const alpha = colorData && colorData.a;
if (colorData) {
// hsl is better than hex between conversions
if (colorData.hsl) {
return setAlpha(colorData.hsl, alpha);
}
if (colorData.hex && colorData.hex.length > 0) {
return setAlpha(colorData.hex, alpha);
}
}
return setAlpha(colorData, alpha);
}
export function changeColor(data, oldHue) {
const colorData = data === '' ? '#2d8cf0' : data;
const color = getColor(data, colorData);
const hsl = color.toHsl();
const hsv = color.toHsv();
if (hsl.s === 0) {
hsl.h = colorData.h || (colorData.hsl && colorData.hsl.h) || oldHue || 0;
hsv.h = hsl.h;
}
// when the hsv.v is less than 0.0164 (base on test)
// because of possible loss of precision
// the result of hue and saturation would be miscalculated
if (hsv.v < 0.0164) {
hsv.h = colorData.h || (colorData.hsv && colorData.hsv.h) || 0;
hsv.s = colorData.s || (colorData.hsv && colorData.hsv.s) || 0;
}
if (hsl.l < 0.01) {
hsl.h = colorData.h || (colorData.hsl && colorData.hsl.h) || 0;
hsl.s = colorData.s || (colorData.hsl && colorData.hsl.s) || 0;
}
return {
hsl,
hex: color.toHexString().toUpperCase(),
rgba: color.toRgb(),
hsv,
oldHue: colorData.h || oldHue || hsl.h,
source: colorData.source,
a: colorData.a || color.getAlpha(),
};
}
export function clamp(value, min, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
export function getIncrement(key, keys, increment) {
return oneOf(key, keys) ? increment : 0;
}
export function getTouches(e, prop) {
return e.touches ? e.touches[0][prop] : 0;
}
export function toRGBAString(rgba) {
const {r, g, b, a} = rgba;
return `rgba(${[r, g, b, a].join(',')})`;
}
export function isValidHex(hex) {
return tinycolor(hex).isValid();
}
function checkIteratee(data, counts, letter) {
let {checked, passed} = counts;
const value = data[letter];
if (value) {
checked += 1;
if (Number.isFinite(value)) {
passed += 1;
}
}
return {checked, passed};
}
const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'];
export function simpleCheckForValidColor(data) {
const results = keysToCheck.reduce(checkIteratee.bind(null, data), {checked: 0, passed: 0});
return results.checked === results.passed ? data : undefined;
}

View File

@@ -0,0 +1 @@
b7bf13de-078d-4f09-934c-3e21c27ffbf8

View File

@@ -0,0 +1,3 @@
import Content from '../layout/content.vue';
export default Content;

View File

@@ -0,0 +1 @@
f3a1f9d2-66b3-4dc2-9aa3-35ccf11a8777

View File

@@ -0,0 +1 @@
d722c2c6-812d-4b6c-9aa0-ce06c9e2681e

View File

@@ -0,0 +1,72 @@
<template>
<div :class="[prefixCls + '-confirm']" @keydown.tab.capture="handleTab">
<i-button :class="timeClasses" size="small" type="text" :disabled="timeDisabled" v-if="showTime" @click="handleToggleTime">
{{labels.time}}
</i-button>
<i-button size="small" @click.native="handleClear" @keydown.enter.native="handleClear">
{{labels.clear}}
</i-button>
<i-button size="small" type="primary" @click.native="handleSuccess" @keydown.enter.native="handleSuccess">
{{labels.ok}}
</i-button>
</div>
</template>
<script>
import iButton from '../../button/button.vue';
import Locale from '../../../mixins/locale';
import Emitter from '../../../mixins/emitter';
const prefixCls = 'ivu-picker';
export default {
mixins: [Locale, Emitter],
components: {iButton},
props: {
showTime: false,
isTime: false,
timeDisabled: false
},
data() {
return {
prefixCls: prefixCls
};
},
computed: {
timeClasses () {
return `${prefixCls}-confirm-time`;
},
labels(){
const labels = ['time', 'clear', 'ok'];
const values = [(this.isTime ? 'selectDate' : 'selectTime'), 'clear', 'ok'];
return labels.reduce((obj, key, i) => {
obj[key] = this.t('i.datepicker.' + values[i]);
return obj;
}, {});
}
},
methods: {
handleClear () {
this.$emit('on-pick-clear');
},
handleSuccess () {
this.$emit('on-pick-success');
},
handleToggleTime () {
if (this.timeDisabled) return;
this.$emit('on-pick-toggle-time');
this.dispatch('CalendarPicker', 'focus-input');
this.dispatch('CalendarPicker', 'update-popper');
},
handleTab(e) {
const tabbables = [...this.$el.children];
const expectedFocus = tabbables[e.shiftKey ? 'shift' : 'pop']();
if (document.activeElement === expectedFocus) {
e.preventDefault();
e.stopPropagation();
this.dispatch('CalendarPicker', 'focus-input');
}
}
}
};
</script>

View File

@@ -0,0 +1,117 @@
<template>
<div :class="classes">
<div :class="[prefixCls + '-header']">
<span v-for="day in headerDays" :key="day">
{{day}}
</span>
</div>
<span
:class="getCellCls(cell)"
v-for="(cell, i) in cells"
:key="String(cell.date) + i"
@click="handleClick(cell, $event)"
@mouseenter="handleMouseMove(cell)"
>
<em>{{ cell.desc }}</em>
</span>
</div>
</template>
<script>
import { clearHours, isInRange } from '../util';
import Locale from '../../../mixins/locale';
import jsCalendar from 'js-calendar';
import mixin from './mixin';
import prefixCls from './prefixCls';
export default {
mixins: [ Locale, mixin ],
props: {
/* more props in mixin */
showWeekNumbers: {
type: Boolean,
default: false
},
},
data () {
return {
prefixCls: prefixCls,
};
},
computed: {
classes () {
return [
`${prefixCls}`,
{
[`${prefixCls}-show-week-numbers`]: this.showWeekNumbers
}
];
},
calendar(){
const weekStartDay = Number(this.t('i.datepicker.weekStartDay'));
return new jsCalendar.Generator({onlyDays: !this.showWeekNumbers, weekStart: weekStartDay});
},
headerDays () {
const weekStartDay = Number(this.t('i.datepicker.weekStartDay'));
const translatedDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'].map(item => {
return this.t('i.datepicker.weeks.' + item);
});
const weekDays = translatedDays.splice(weekStartDay, 7 - weekStartDay).concat(translatedDays.splice(0, weekStartDay));
return this.showWeekNumbers ? [''].concat(weekDays) : weekDays;
},
cells () {
const tableYear = this.tableDate.getFullYear();
const tableMonth = this.tableDate.getMonth();
const today = clearHours(new Date()); // timestamp of today
const selectedDays = this.dates.filter(Boolean).map(clearHours); // timestamp of selected days
const [minDay, maxDay] = this.dates.map(clearHours);
const rangeStart = this.rangeState.from && clearHours(this.rangeState.from);
const rangeEnd = this.rangeState.to && clearHours(this.rangeState.to);
const isRange = this.selectionMode === 'range';
const disabledTestFn = typeof this.disabledDate === 'function' && this.disabledDate;
return this.calendar(tableYear, tableMonth, (cell) => {
// normalize date offset from the dates provided by jsCalendar
// Comment out this code to fix daylight saving time bug
// https://www.cnblogs.com/hamsterPP/p/5415472.html
if (cell.date instanceof Date) cell.date.setTime(cell.date.getTime() + cell.date.getTimezoneOffset() * 60000 + 480 * 60 * 1000);
//if (cell.date instanceof Date) cell.date.setTime(clearHours(cell.date));
const time = cell.date && clearHours(cell.date);
const dateIsInCurrentMonth = cell.date && tableMonth === cell.date.getMonth();
return {
...cell,
type: time === today ? 'today' : cell.type,
selected: dateIsInCurrentMonth && selectedDays.includes(time),
disabled: (cell.date && disabledTestFn) && disabledTestFn(new Date(time)),
range: dateIsInCurrentMonth && isRange && isInRange(time, rangeStart, rangeEnd),
start: dateIsInCurrentMonth && isRange && time === minDay,
end: dateIsInCurrentMonth && isRange && time === maxDay
};
}).cells.slice(this.showWeekNumbers ? 8 : 0);
}
},
methods: {
getCellCls (cell) {
return [
`${prefixCls}-cell`,
{
[`${prefixCls}-cell-selected`]: cell.selected || cell.start || cell.end,
[`${prefixCls}-cell-disabled`]: cell.disabled,
[`${prefixCls}-cell-today`]: cell.type === 'today',
[`${prefixCls}-cell-prev-month`]: cell.type === 'prevMonth',
[`${prefixCls}-cell-next-month`]: cell.type === 'nextMonth',
[`${prefixCls}-cell-week-label`]: cell.type === 'weekLabel',
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end,
[`${prefixCls}-focused`]: clearHours(cell.date) === clearHours(this.focusedDate)
}
];
},
}
};
</script>

View File

@@ -0,0 +1,57 @@
import {clearHours} from '../util';
export default {
name: 'PanelTable',
props: {
tableDate: {
type: Date,
required: true
},
disabledDate: {
type: Function
},
selectionMode: {
type: String,
required: true
},
value: {
type: Array,
required: true
},
rangeState: {
type: Object,
default: () => ({
from: null,
to: null,
selecting: false
})
},
focusedDate: {
type: Date,
required: true,
}
},
computed: {
dates(){
const {selectionMode, value, rangeState} = this;
const rangeSelecting = selectionMode === 'range' && rangeState.selecting;
return rangeSelecting ? [rangeState.from] : value;
},
},
methods: {
handleClick (cell) {
if (cell.disabled || cell.type === 'weekLabel') return;
const newDate = new Date(clearHours(cell.date));
this.$emit('on-pick', newDate);
this.$emit('on-pick-click');
},
handleMouseMove (cell) {
if (!this.rangeState.selecting) return;
if (cell.disabled) return;
const newDate = cell.date;
this.$emit('on-change-range', newDate);
},
}
};

Some files were not shown because too many files have changed in this diff Show More