pull/9/head
tangjinzhou 2018-01-16 15:41:00 +08:00
parent 127a67d53d
commit 1b8ecf5656
16 changed files with 880 additions and 327 deletions

View File

@ -1,5 +0,0 @@
export default (instance, prop) => {
const $options = instance.$options || {}
const propsData = $options.propsData || {}
return prop in propsData
}

View File

@ -44,9 +44,9 @@ const animation = {
leave (node, done) { leave (node, done) {
return animate(node, false, done) return animate(node, false, done)
}, },
appear (node, done) { // appear (node, done) {
return animate(node, true, done) // return animate(node, true, done)
}, // },
} }
export default animation export default animation

View File

@ -39,8 +39,8 @@ export default {
disabled: PropTypes.bool.def(false), disabled: PropTypes.bool.def(false),
}, },
data () { data () {
this.aligned = false
return { return {
aligned: false,
} }
}, },
mounted () { mounted () {
@ -103,7 +103,6 @@ export default {
if (!props.disabled) { if (!props.disabled) {
const source = this.$el const source = this.$el
this.aligned = true this.aligned = true
// this.$emit('align', source, align(source, props.target(), props.align))
this.$listeners.align && this.$listeners.align(source, align(source, props.target(), props.align)) this.$listeners.align && this.$listeners.align(source, align(source, props.target(), props.align))
} }
}, },

View File

@ -1,17 +1,3 @@
<template>
<label :class="classes">
<span :class="checkboxClass">
<input :name="name" type="checkbox" :disabled="disabled"
:class="`${prefixCls}-input`" :checked="stateChecked"
@change="handleChange"
/>
<span :class="`${prefixCls}-inner`" />
</span>
<span v-if="hasDefaultSlot">
<slot></slot>
</span>
</label>
</template>
<script> <script>
import hasProp from '../_util/props-util' import hasProp from '../_util/props-util'
export default { export default {
@ -33,58 +19,48 @@ export default {
prop: 'checked', prop: 'checked',
}, },
inject: { inject: {
checkboxGroupContext: { default: undefined }, checkboxGroupContext: { default: null },
}, },
data () { data () {
const { checkboxGroupContext, checked, defaultChecked, value } = this const { checkboxGroupContext, checked, defaultChecked, value } = this
let stateChecked let sChecked
if (checkboxGroupContext && checkboxGroupContext.checkedStatus) { if (checkboxGroupContext) {
stateChecked = checkboxGroupContext.checkedStatus.has(value) sChecked = checkboxGroupContext.sValue.indexOf(value) !== -1
} else {
sChecked = !hasProp(this, 'checked') ? defaultChecked : checked
} }
return { return {
stateChecked: stateChecked === undefined sChecked,
? !hasProp(this, 'checked') ? defaultChecked : checked
: stateChecked,
} }
}, },
computed: { computed: {
hasDefaultSlot () {
return !!this.$slots.default
},
classes () {
const { prefixCls } = this
return {
[`${prefixCls}-wrapper`]: true,
}
},
checkboxClass () { checkboxClass () {
const { prefixCls, indeterminate, stateChecked, disabled } = this const { prefixCls, indeterminate, sChecked, $props, checkboxGroupContext } = this
let disabled = $props.disabled
if (checkboxGroupContext) {
disabled = disabled || checkboxGroupContext.disabled
}
return { return {
[`${prefixCls}`]: true, [`${prefixCls}`]: true,
[`${prefixCls}-checked`]: stateChecked, [`${prefixCls}-checked`]: sChecked,
[`${prefixCls}-disabled`]: disabled, [`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-indeterminate`]: indeterminate, [`${prefixCls}-indeterminate`]: indeterminate,
} }
}, },
}, },
mounted () {
},
methods: { methods: {
handleChange (event) { handleChange (event) {
const targetChecked = event.target.checked const targetChecked = event.target.checked
this.$emit('input', targetChecked) this.$emit('input', targetChecked)
const { name, value, checked, checkboxGroupContext, stateChecked } = this const { name, value, checked, checkboxGroupContext, sChecked } = this
if ((checked === undefined && !checkboxGroupContext) || (checkboxGroupContext && checkboxGroupContext.value === undefined)) { if ((checked === undefined && !checkboxGroupContext) || (checkboxGroupContext && checkboxGroupContext.sValue === undefined)) {
this.stateChecked = targetChecked this.sChecked = targetChecked
} }
const target = { const target = {
name, name,
value, value,
checked: !stateChecked, checked: !sChecked,
} }
if (this.checkboxGroupContext) {
this.checkboxGroupContext.handleChange({ target })
} else {
this.$emit('change', { this.$emit('change', {
target, target,
stopPropagation () { stopPropagation () {
@ -94,16 +70,55 @@ export default {
event.preventDefault() event.preventDefault()
}, },
}) })
} },
onMouseEnter (e) {
this.$emit('mouseenter', e)
},
onMouseLeave (e) {
this.$emit('mouseleave', e)
},
focus () {
this.$refs.input.focus()
},
blur () {
this.$refs.input.blur()
}, },
}, },
watch: { watch: {
checked (val) { checked (val) {
this.stateChecked = val this.sChecked = val
}, },
'checkboxGroupContext.checkedStatus': function (checkedStatus) { 'checkboxGroupContext.sValue': function (val) {
this.stateChecked = checkedStatus.has(this.value) this.sChecked = val.indexOf(this.value) !== -1
}, },
}, },
render () {
const { $props: props, checkboxGroupContext, checkboxClass, name, $slots, sChecked } = this
const {
prefixCls,
} = props
let disabled = props.disabled
let onChange = this.handleChange
if (checkboxGroupContext) {
onChange = () => checkboxGroupContext.toggleOption({ value: props.value })
disabled = props.disabled || checkboxGroupContext.disabled
}
return (
<label
class={`${prefixCls}-wrapper`}
onMouseenter={this.onMouseEnter}
onMouseleave={this.onMouseLeave}
>
<span class={checkboxClass}>
<input name={name} type='checkbox' disabled={disabled}
class={`${prefixCls}-input`} checked={sChecked}
onChange={onChange} ref='input'
/>
<span class={`${prefixCls}-inner`} />
</span>
{$slots.default ? <span>{$slots.default}</span> : null}
</label>
)
},
} }
</script> </script>

View File

@ -1,11 +1,3 @@
<template>
<div :class="`${prefixCls}`">
<Checkbox v-for="item in checkOptions" :key="item.value" :value="item.value" :disabled="item.disabled">
{{item.label}}
</Checkbox>
<slot v-if="checkOptions.length === 0"></slot>
</div>
</template>
<script> <script>
import Checkbox from './Checkbox.vue' import Checkbox from './Checkbox.vue'
import hasProp from '../_util/props-util' import hasProp from '../_util/props-util'
@ -41,52 +33,84 @@ export default {
data () { data () {
const { value, defaultValue } = this const { value, defaultValue } = this
return { return {
stateValue: value || defaultValue, sValue: value || defaultValue,
} }
}, },
computed: {
checkedStatus () {
return new Set(this.stateValue)
},
checkOptions () {
const { disabled } = this
return this.options.map(option => {
return typeof option === 'string'
? { label: option, value: option }
: { ...option, disabled: option.disabled === undefined ? disabled : option.disabled }
})
},
},
methods: { methods: {
handleChange (event) { handleChange (event) {
const target = event.target const target = event.target
const { value: targetValue, checked } = target const { value: targetValue, checked } = target
const { stateValue } = this const { sValue } = this
let newVal = [] let newVal = []
if (checked) { if (checked) {
newVal = [...stateValue, targetValue] newVal = [...sValue, targetValue]
} else { } else {
newVal = [...stateValue] newVal = [...sValue]
const index = newVal.indexOf(targetValue) const index = newVal.indexOf(targetValue)
index >= 0 && newVal.splice(index, 1) index >= 0 && newVal.splice(index, 1)
} }
newVal = [...new Set(newVal)] newVal = [...new Set(newVal)]
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.stateValue = newVal this.sValue = newVal
} }
this.$emit('input', newVal) this.$emit('input', newVal)
this.$emit('change', newVal) this.$emit('change', newVal)
}, },
getOptions () {
const { options } = this.$props
return options.map(option => {
if (typeof option === 'string') {
return {
label: option,
value: option,
}
}
return option
})
}, },
mounted () { toggleOption (option) {
const optionIndex = this.sValue.indexOf(option.value)
const value = [...this.sValue]
if (optionIndex === -1) {
value.push(option.value)
} else {
value.splice(optionIndex, 1)
}
if (!hasProp(this, 'value')) {
this.sValue = value
}
this.$emit('input', value)
this.$emit('change', value)
},
},
render () {
const { $props: props, $data: state, $slots } = this
const { prefixCls, options } = props
let children = $slots.default
if (options && options.length > 0) {
children = this.getOptions().map(option => (
<Checkbox
key={option.value}
disabled={'disabled' in option ? option.disabled : props.disabled}
value={option.value}
checked={state.sValue.indexOf(option.value) !== -1}
onChange={() => this.toggleOption(option)}
class={`${prefixCls}-item`}
>
{option.label}
</Checkbox>
))
}
return (
<div class={prefixCls}>
{children}
</div>
)
}, },
watch: { watch: {
value (val) { value (val) {
this.stateValue = val this.sValue = val
}, },
}, },
components: {
Checkbox,
},
} }
</script> </script>

View File

@ -0,0 +1,40 @@
<script>
import { Item, itemProps } from './src/index'
import { getClass, getStyle } from '../_util/vnode'
import Tooltip from '../tooltip'
export default {
props: itemProps,
inject: {
inlineCollapsed: { default: false },
},
isMenuItem: 1,
methods: {
onKeyDown (e) {
this.$refs.menuItem.onKeyDown(e)
},
},
render () {
const { inlineCollapsed, $props: props, $slots, $attrs: attrs, $listeners } = this
const itemProps = {
props,
attrs,
on: $listeners,
class: getClass(this),
style: getStyle(this),
}
return <Tooltip
placement='right'
overlayClassName={`${props.rootPrefixCls}-inline-collapsed-tooltip`}
>
<template slot='title'>
{inlineCollapsed && props.level === 1 ? $slots.default : ''}
</template>
<Item {...itemProps} ref='menuItem'>
{$slots.default}
</Item>
</Tooltip>
},
}
</script>

208
components/menu/index.vue Normal file
View File

@ -0,0 +1,208 @@
<script>
import RcMenu, { Divider, ItemGroup, SubMenu } from '../src'
import PropTypes from '../util/vue-types'
import animation from '../_util/openAnimation'
import warning from '../_util/warning'
import Item from './MenuItem'
import { hasProp } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
export const MenuMode = PropTypes.oneOf(['vertical', 'vertical-left', 'vertical-right', 'horizontal', 'inline'])
export const menuProps = {
theme: PropTypes.oneOf(['light', 'dark']).def('light'),
mode: MenuMode,
selectable: PropTypes.bool,
selectedKeys: PropTypes.array,
defaultSelectedKeys: PropTypes.array,
openKeys: PropTypes.array,
defaultOpenKeys: PropTypes.array,
// onOpenChange: (openKeys: string[]) => void;
// onSelect: (param: SelectParam) => void;
// onDeselect: (param: SelectParam) => void;
// onClick: (param: ClickParam) => void;
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
openTransitionName: PropTypes.string,
prefixCls: PropTypes.string.def('ant-menu'),
multiple: PropTypes.bool,
inlineIndent: PropTypes.number.def(24),
inlineCollapsed: PropTypes.bool,
}
export default {
props: menuProps,
Divider,
Item,
SubMenu,
ItemGroup,
provide () {
return {
inlineCollapsed: this.getInlineCollapsed(),
antdMenuTheme: this.$props.theme,
}
},
mixins: [BaseMixin],
inject: {
siderCollapsed: { default: undefined },
collapsedWidth: { default: undefined },
},
data () {
const props = this.$props
warning(
!(hasProp(this, 'inlineCollapsed') && props.mode !== 'inline'),
'`inlineCollapsed` should only be used when Menu\'s `mode` is inline.',
)
this.switchModeFromInline = false
this.leaveAnimationExecutedWhenInlineCollapsed = false
this.inlineOpenKeys = []
let sOpenKeys
if (hasProp(this, 'defaultOpenKeys')) {
sOpenKeys = props.defaultOpenKeys
} else if (hasProp(this, 'openKeys')) {
sOpenKeys = props.openKeys
}
return {
sOpenKeys,
}
},
methods: {
handleClick (e) {
this.handleOpenChange([])
const { onClick } = this.props
if (onClick) {
onClick(e)
}
},
handleOpenChange (openKeys) {
this.setOpenKeys(openKeys)
const { onOpenChange } = this.props
if (onOpenChange) {
onOpenChange(openKeys)
}
},
setOpenKeys (openKeys) {
if (!('openKeys' in this.props)) {
this.setState({ openKeys })
}
},
getRealMenuMode () {
const inlineCollapsed = this.getInlineCollapsed()
if (this.switchModeFromInline && inlineCollapsed) {
return 'inline'
}
const { mode } = this.props
return inlineCollapsed ? 'vertical' : mode
},
getInlineCollapsed () {
const { inlineCollapsed } = this.props
if (this.context.siderCollapsed !== undefined) {
return this.context.siderCollapsed
}
return inlineCollapsed
},
getMenuOpenAnimation (menuMode) {
const { openAnimation, openTransitionName } = this.props
let menuOpenAnimation = openAnimation || openTransitionName
if (openAnimation === undefined && openTransitionName === undefined) {
switch (menuMode) {
case 'horizontal':
menuOpenAnimation = 'slide-up'
break
case 'vertical':
case 'vertical-left':
case 'vertical-right':
// When mode switch from inline
// submenu should hide without animation
if (this.switchModeFromInline) {
menuOpenAnimation = ''
this.switchModeFromInline = false
} else {
menuOpenAnimation = 'zoom-big'
}
break
case 'inline':
menuOpenAnimation = {
...animation,
leave: (node, done: () => void) => animation.leave(node, () => {
// Make sure inline menu leave animation finished before mode is switched
this.switchModeFromInline = false
this.setState({})
// when inlineCollapsed change false to true, all submenu will be unmounted,
// so that we don't need handle animation leaving.
if (this.getRealMenuMode() === 'vertical') {
return
}
done()
}),
}
break
default:
}
}
return menuOpenAnimation
},
},
componentWillReceiveProps (nextProps, nextContext) {
const { prefixCls } = this.props
if (this.props.mode === 'inline' &&
nextProps.mode !== 'inline') {
this.switchModeFromInline = true
}
if ('openKeys' in nextProps) {
this.setState({ openKeys: nextProps.openKeys })
return
}
if ((nextProps.inlineCollapsed && !this.props.inlineCollapsed) ||
(nextContext.siderCollapsed && !this.context.siderCollapsed)) {
this.switchModeFromInline =
!!this.state.openKeys.length && !!this.$el.querySelectorAll(`.${prefixCls}-submenu-open`).length
this.inlineOpenKeys = this.state.openKeys
this.setState({ openKeys: [] })
}
if ((!nextProps.inlineCollapsed && this.props.inlineCollapsed) ||
(!nextContext.siderCollapsed && this.context.siderCollapsed)) {
this.setState({ openKeys: this.inlineOpenKeys })
this.inlineOpenKeys = []
}
},
render () {
const { prefixCls, className, theme } = this.props
const menuMode = this.getRealMenuMode()
const menuOpenAnimation = this.getMenuOpenAnimation(menuMode)
const menuClassName = {
[`${prefixCls}-${theme}`]: true,
[`${prefixCls}-inline-collapsed`]: this.getInlineCollapsed(),
}
const menuProps = {
openKeys: this.state.openKeys,
onOpenChange: this.handleOpenChange,
className: menuClassName,
mode: menuMode,
}
if (menuMode !== 'inline') {
// closing vertical popup submenu after click it
menuProps.onClick = this.handleClick
menuProps.openTransitionName = menuOpenAnimation
} else {
menuProps.openAnimation = menuOpenAnimation
}
// https://github.com/ant-design/ant-design/issues/8587
const { collapsedWidth } = this.context
if (
this.getInlineCollapsed() &&
(collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px')
) {
return null
}
return <RcMenu {...this.props} {...menuProps} />
},
}
</script>

View File

@ -3,11 +3,7 @@ import PropTypes from '../../_util/vue-types'
import KeyCode from '../../_util/KeyCode' import KeyCode from '../../_util/KeyCode'
import { noop } from './util' import { noop } from './util'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
const props = {
const MenuItem = {
name: 'MenuItem',
props: {
rootPrefixCls: PropTypes.string, rootPrefixCls: PropTypes.string,
eventKey: PropTypes.string, eventKey: PropTypes.string,
active: PropTypes.bool, active: PropTypes.bool,
@ -20,7 +16,10 @@ const MenuItem = {
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'), mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
parentMenu: PropTypes.object, parentMenu: PropTypes.object,
clearSubMenuTimers: PropTypes.func.def(noop), clearSubMenuTimers: PropTypes.func.def(noop),
}, }
const MenuItem = {
name: 'MenuItem',
props,
inject: { inject: {
parentMenuContext: { default: undefined }, parentMenuContext: { default: undefined },
}, },
@ -162,4 +161,5 @@ const MenuItem = {
} }
export default MenuItem export default MenuItem
export { props as menuItemProps }
</script> </script>

View File

@ -18,13 +18,11 @@ const popupPlacementMap = {
export default { export default {
name: 'SubMenu', name: 'SubMenu',
props: { props: {
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'), mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
title: PropTypes.any.def(''), title: PropTypes.any.def(''),
selectedKeys: PropTypes.array.def([]), selectedKeys: PropTypes.array.def([]),
openKeys: PropTypes.array.def([]), openKeys: PropTypes.array.def([]),
// onClick: PropTypes.func,
openChange: PropTypes.func.def(noop), openChange: PropTypes.func.def(noop),
rootPrefixCls: PropTypes.string, rootPrefixCls: PropTypes.string,
eventKey: PropTypes.string, eventKey: PropTypes.string,
@ -32,8 +30,6 @@ export default {
active: PropTypes.bool, // TODO: remove active: PropTypes.bool, // TODO: remove
isRootMenu: PropTypes.bool, isRootMenu: PropTypes.bool,
index: PropTypes.number, index: PropTypes.number,
// onItemHover: PropTypes.func,
// onSelect: PropTypes.func,
triggerSubMenuAction: PropTypes.string, triggerSubMenuAction: PropTypes.string,
popupClassName: PropTypes.string, popupClassName: PropTypes.string,
getPopupContainer: PropTypes.func, getPopupContainer: PropTypes.func,
@ -48,6 +44,7 @@ export default {
}, },
inject: { inject: {
parentMenuContext: { default: undefined }, parentMenuContext: { default: undefined },
antdMenuTheme: { default: 'light' },
}, },
mixins: [BaseMixin], mixins: [BaseMixin],
isSubMenu: true, isSubMenu: true,
@ -324,6 +321,7 @@ export default {
render (h) { render (h) {
const props = this.$props const props = this.$props
const { rootPrefixCls, antdMenuTheme } = this
const isOpen = this.isOpen() const isOpen = this.isOpen()
const prefixCls = this.getPrefixCls() const prefixCls = this.getPrefixCls()
const isInlineMode = props.mode === 'inline' const isInlineMode = props.mode === 'inline'
@ -440,7 +438,7 @@ export default {
{!isInlineMode && ( {!isInlineMode && (
<Trigger <Trigger
prefixCls={prefixCls} prefixCls={prefixCls}
popupClassName={`${prefixCls}-popup ${popupClassName || ''}`} popupClassName={`${prefixCls}-popup ${rootPrefixCls}-${antdMenuTheme} ${popupClassName || ''}`}
getPopupContainer={getPopupContainer} getPopupContainer={getPopupContainer}
builtinPlacements={placements} builtinPlacements={placements}
popupPlacement={popupPlacement} popupPlacement={popupPlacement}

View File

@ -1,6 +1,6 @@
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
export default { export default {
prefixCls: PropTypes.string.def('rc-menu'), prefixCls: PropTypes.string.def('ant-menu'),
focusable: PropTypes.bool.def(true), focusable: PropTypes.bool.def(true),
multiple: PropTypes.bool, multiple: PropTypes.bool,
defaultActiveFirst: PropTypes.bool, defaultActiveFirst: PropTypes.bool,

View File

@ -1,9 +1,9 @@
import Menu from './Menu' import Menu from './Menu'
import SubMenu from './SubMenu' import SubMenu from './SubMenu'
import MenuItem from './MenuItem' import MenuItem, { menuItemProps } from './MenuItem'
import MenuItemGroup from './MenuItemGroup' import MenuItemGroup from './MenuItemGroup'
import Divider from './Divider' import Divider from './Divider'
export { SubMenu, MenuItem as Item, MenuItem, MenuItemGroup, MenuItemGroup as ItemGroup, Divider } export { SubMenu, MenuItem as Item, menuItemProps as itemProps, MenuItem, MenuItemGroup, MenuItemGroup as ItemGroup, Divider }
export default Menu export default Menu

View File

@ -0,0 +1,118 @@
.@{menu-prefix-cls} {
// dark theme
&-dark,
&-dark &-sub {
color: @text-color-secondary-dark;
background: @menu-dark-bg;
.@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
opacity: .45;
transition: all .3s;
&:after,
&:before {
background: #fff;
}
}
}
&-dark&-submenu-popup {
background: transparent;
}
&-dark &-inline&-sub {
background: @menu-dark-submenu-bg;
box-shadow: 0 2px 8px rgba(0, 0, 0, .45) inset;
}
&-dark&-horizontal {
border-bottom-color: @menu-dark-bg;
}
&-dark&-horizontal > &-item,
&-dark&-horizontal > &-submenu {
border-color: @menu-dark-bg;
border-bottom: 0;
}
&-dark &-item,
&-dark &-item-group-title,
&-dark &-item > a {
color: @text-color-secondary-dark;
}
&-dark&-inline,
&-dark&-vertical,
&-dark&-vertical-left,
&-dark&-vertical-right {
border-right: 0;
}
&-dark&-inline &-item,
&-dark&-vertical &-item,
&-dark&-vertical-left &-item,
&-dark&-vertical-right &-item {
border-right: 0;
margin-left: 0;
left: 0;
&:after {
border-right: 0;
}
}
&-dark&-inline &-item,
&-dark&-inline &-submenu-title {
width: 100%;
}
&-dark &-item:hover,
&-dark &-item-active,
&-dark &-submenu-active,
&-dark &-submenu-open,
&-dark &-submenu-selected,
&-dark &-submenu-title:hover {
background-color: transparent;
color: #fff;
> a {
color: #fff;
}
> .@{menu-prefix-cls}-submenu-title,
> .@{menu-prefix-cls}-submenu-title:hover {
> .@{menu-prefix-cls}-submenu-arrow {
opacity: 1;
&:after,
&:before {
background: #fff;
}
}
}
}
&-dark &-item-selected {
border-right: 0;
color: #fff;
&:after {
border-right: 0;
}
> a,
> a:hover {
color: #fff;
}
}
&&-dark &-item-selected,
&-submenu-popup&-dark &-item-selected {
background-color: @primary-color;
}
// Disabled state sets text to dark gray and nukes hover/tab effects
&-dark &-item-disabled,
&-dark &-submenu-disabled {
&,
> a {
opacity: 0.8;
color: @disabled-color-dark !important;
}
> .@{menu-prefix-cls}-submenu-title {
color: @disabled-color-dark !important;
}
}
}

View File

@ -1,2 +1,5 @@
import '../../style/index.less' import '../../style/index.less'
import './index.less' import './index.less'
// style dependencies
import '../../tooltip/style'

View File

@ -1,64 +1,144 @@
@menuPrefixCls: rc-menu; @import "../../style/themes/default";
@import "../../style/mixins/index";
@font-face { @menu-prefix-cls: ~"@{ant-prefix}-menu";
font-family: 'FontAwesome'; @menu-inline-toplevel-item-height: 40px;
src: url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?v=4.2.0'); @menu-item-height: 40px;
src: url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('https://cdn.bootcss.com/font-awesome/4.2.0/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
.@{menuPrefixCls} { // default theme
.@{menu-prefix-cls} {
.reset-component;
outline: none; outline: none;
margin-bottom: 0; margin-bottom: 0;
padding-left: 0; // Override default ul/ol padding-left: 0; // Override default ul/ol
list-style: none; list-style: none;
border: 1px solid #d9d9d9; box-shadow: @box-shadow-base;
box-shadow: 0 0 4px #d9d9d9; background: @component-background;
border-radius: 3px; line-height: 0; // Fix display inline-block gap
color: #666; transition: background .3s, width .2s;
.clearfix;
ul,
ol {
list-style: none;
margin: 0;
padding: 0;
}
&-hidden { &-hidden {
display: none; display: none;
} }
&-collapse {
overflow: hidden;
&-active {
overflow: hidden;
transition: height .3s ease-out;
}
}
&-item-group-list {
margin: 0;
padding: 0;
}
&-item-group-title { &-item-group-title {
color: #999; color: @text-color-secondary;
line-height: 1.5; font-size: @font-size-base;
padding: 8px 10px; line-height: @line-height-base;
border-bottom: 1px solid #dedede; padding: 8px 16px;
transition: all .3s;
} }
&-submenu,
&-submenu-inline {
transition: border-color .3s @ease-in-out, background .3s @ease-in-out, padding .15s @ease-in-out;
}
&-item:active,
&-submenu-title:active {
background: @item-active-bg;
}
&-submenu &-sub {
cursor: initial;
transition: background .3s @ease-in-out, padding .3s @ease-in-out;
}
&-item > a {
display: block;
color: @text-color;
&:hover {
color: @primary-color;
}
&:focus {
text-decoration: none;
}
&:before {
position: absolute;
background-color: transparent;
width: 100%;
height: 100%;
top: 0;
left: 0;
bottom: 0;
right: 0;
content: '';
}
}
&-item-divider {
height: 1px;
overflow: hidden;
background-color: @border-color-split;
line-height: 0;
}
&-item:hover,
&-item-active, &-item-active,
&-submenu-active > span > &-submenu-title { &:not(&-inline) &-submenu-open,
background-color: #eaf8fe; &-submenu-active,
&-submenu-title:hover {
color: @primary-color;
}
&-horizontal &-item,
&-horizontal &-submenu {
margin-top: -1px;
}
&-horizontal > &-item:hover,
&-horizontal > &-item-active,
&-horizontal > &-submenu &-submenu-title:hover {
background-color: transparent;
} }
&-item-selected { &-item-selected {
background-color: #eaf8fe; color: @primary-color;
// fix chrome render bug > a,
transform: translateZ(0); > a:hover {
color: @primary-color;
}
} }
&-submenu-selected { &:not(&-horizontal) &-item-selected {
background-color: #eaf8fe; background-color: @item-active-bg;
} }
& > li&-submenu { &-inline,
&-vertical,
&-vertical-left {
border-right: @border-width-base @border-style-base @border-color-split;
}
&-vertical-right {
border-left: @border-width-base @border-style-base @border-color-split;
}
&-vertical&-sub,
&-vertical-left&-sub,
&-vertical-right&-sub {
border-right: 0;
padding: 0; padding: 0;
transform-origin: 0 0;
.@{menu-prefix-cls}-item {
border-right: 0;
margin-left: 0;
left: 0;
&:after {
border-right: 0;
}
}
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu {
transform-origin: 0 0;
}
} }
&-horizontal&-sub, &-horizontal&-sub,
@ -66,67 +146,147 @@
&-vertical-left&-sub, &-vertical-left&-sub,
&-vertical-right&-sub { &-vertical-right&-sub {
min-width: 160px; min-width: 160px;
margin-top: 0;
} }
&-item, &-submenu-title { &-item,
&-submenu-title {
cursor: pointer;
margin: 0; margin: 0;
padding: 0 20px;
position: relative; position: relative;
display: block; display: block;
padding: 7px 7px 7px 16px;
white-space: nowrap; white-space: nowrap;
transition: color .3s @ease-in-out, border-color .3s @ease-in-out, background .3s @ease-in-out, padding .15s @ease-in-out;
.@{iconfont-css-prefix} {
min-width: 14px;
margin-right: 10px;
transition: font-size .15s @ease-out, margin .3s @ease-in-out;
+ span {
transition: opacity .3s @ease-in-out, width .3s @ease-in-out;
opacity: 1;
}
}
}
// Disabled state sets text to gray and nukes hover/tab effects
&.@{menuPrefixCls}-item-disabled, &.@{menuPrefixCls}-submenu-disabled {
color: #777 !important;
}
}
& > &-item-divider { & > &-item-divider {
height: 1px; height: 1px;
margin: 1px 0; margin: 1px 0;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
line-height: 0; line-height: 0;
background-color: #e5e5e5; background-color: @border-color-split;
} }
&-submenu { &-submenu {
&-popup { &-popup {
position: absolute; position: absolute;
border-radius: @border-radius-base;
z-index: @zindex-dropdown;
} }
> .@{menuPrefixCls} {
background-color: #fff; > .@{menu-prefix-cls} {
background-color: @component-background;
border-radius: @border-radius-base;
&-submenu-title:after {
transition: transform .3s @ease-in-out;
} }
} }
.@{menuPrefixCls}-submenu-title, .@{menuPrefixCls}-item { &-vertical,
.anticon { &-vertical-left,
width: 14px; &-vertical-right,
height: 14px; &-inline {
margin-right: 8px; > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
top: -1px; transition: transform .3s @ease-in-out;
position: absolute;
top: 50%;
right: 16px;
width: 10px;
&:before,
&:after {
content: '';
position: absolute;
vertical-align: baseline;
background: #fff;
background-image: linear-gradient(to right, @text-color, @text-color);
width: 6px;
height: 1.5px;
border-radius: 2px;
transition: background .3s @ease-in-out, transform .3s @ease-in-out, top .3s @ease-in-out;
}
&:before {
transform: rotate(45deg) translateY(-2px);
}
&:after {
transform: rotate(-45deg) translateY(2px);
}
}
> .@{menu-prefix-cls}-submenu-title:hover .@{menu-prefix-cls}-submenu-arrow {
&:after,
&:before {
background: linear-gradient(to right, @primary-color, @primary-color);
}
}
}
&-inline > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
&:before {
transform: rotate(-45deg) translateX(2px);
}
&:after {
transform: rotate(45deg) translateX(-2px);
}
}
&-open {
&.@{menu-prefix-cls}-submenu-inline > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
transform: translateY(-2px);
&:after {
transform: rotate(-45deg) translateX(-2px);
}
&:before {
transform: rotate(45deg) translateX(2px);
}
}
}
}
&-vertical &-submenu-selected,
&-vertical-left &-submenu-selected,
&-vertical-right &-submenu-selected {
color: @primary-color;
> a {
color: @primary-color;
} }
} }
&-horizontal { &-horizontal {
background-color: #F3F5F7; border: 0;
border: none; border-bottom: @border-width-base @border-style-base @border-color-split;
border-bottom: 1px solid transparent;
border-bottom: 1px solid #d9d9d9;
box-shadow: none; box-shadow: none;
line-height: 46px;
& > .@{menuPrefixCls}-item, & > .@{menuPrefixCls}-submenu .@{menuPrefixCls}-submenu-title { > .@{menu-prefix-cls}-item,
padding: 15px 20px; > .@{menu-prefix-cls}-submenu {
} position: relative;
top: 1px;
& > .@{menuPrefixCls}-submenu, & > .@{menuPrefixCls}-item {
float: left; float: left;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
&-active { &:hover,
border-bottom: 2px solid #2db7f5; &-active,
background-color: #F3F5F7; &-open,
color: #2baee9; &-selected {
border-bottom: 2px solid @primary-color;
color: @primary-color;
}
> a {
display: block;
color: @text-color;
&:hover {
color: @primary-color;
}
} }
} }
@ -137,169 +297,162 @@
clear: both; clear: both;
} }
} }
&-inline {
overflow: hidden;
}
&-vertical, &-vertical,
&-vertical-left, &-vertical-left,
&-vertical-right, &-vertical-right,
&-inline { &-inline {
padding: 12px 0; .@{menu-prefix-cls}-item {
& > .@{menuPrefixCls}-item, & > .@{menuPrefixCls}-submenu .@{menuPrefixCls}-submenu-title { position: relative;
padding: 12px 8px 12px 24px; &:after {
} content: "";
.@{menuPrefixCls}-submenu-arrow {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
vertical-align: baseline;
text-align: center;
text-transform: none;
text-rendering: auto;
position: absolute; position: absolute;
right: 16px; right: 0;
line-height: 1.5em; top: 0;
&:before { bottom: 0;
content: "\f0da"; border-right: 3px solid @primary-color;
} transform: scaleY(.0001);
} opacity: 0;
} transition: transform .15s @ease-out, opacity .15s @ease-out;
&-inline {
.@{menuPrefixCls}-submenu-arrow {
transform: rotate(90deg);
transition: transform .3s;
}
& .@{menuPrefixCls}-submenu-open > .@{menuPrefixCls}-submenu-title {
.@{menuPrefixCls}-submenu-arrow {
transform: rotate(-90deg);
}
} }
} }
&-vertical&-sub, .@{menu-prefix-cls}-item,
&-vertical-left&-sub, .@{menu-prefix-cls}-submenu-title {
&-vertical-right&-sub { padding: 0 16px;
font-size: @font-size-base;
line-height: @menu-item-height;
height: @menu-item-height;
margin-top: 4px;
margin-bottom: 4px;
overflow: hidden;
text-overflow: ellipsis;
}
// disable margin collapsed
.@{menu-prefix-cls}-submenu {
padding-bottom: 0.01px;
}
.@{menu-prefix-cls}-item:not(:last-child) {
margin-bottom: 8px;
}
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
line-height: @menu-inline-toplevel-item-height;
height: @menu-inline-toplevel-item-height;
}
}
&-inline {
width: 100%;
.@{menu-prefix-cls}-selected,
.@{menu-prefix-cls}-item-selected {
&:after {
transition: transform .15s @ease-in-out, opacity .15s @ease-in-out;
opacity: 1;
transform: scaleY(1);
}
}
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
width: ~"calc(100% + 1px)";
}
}
&-inline-collapsed {
width: @menu-collapsed-width;
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-item-group > .@{menu-prefix-cls}-item-group-list > .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
left: 0;
text-overflow: clip;
padding: 0 (@menu-collapsed-width - 16px) / 2 !important;
.@{menu-prefix-cls}-submenu-arrow {
display: none;
}
.@{iconfont-css-prefix} {
font-size: 16px;
line-height: @menu-item-height;
margin: 0;
+ span {
max-width: 0;
display: inline-block;
opacity: 0;
}
}
}
&-tooltip {
pointer-events: none;
.@{iconfont-css-prefix} {
display: none;
}
a {
color: @text-color-dark;
}
}
.@{menu-prefix-cls}-item-group-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-left: 4px;
padding-right: 4px;
}
}
&-item-group-list {
margin: 0;
padding: 0; padding: 0;
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px 0 28px;
}
}
&-root&-vertical,
&-root&-vertical-left,
&-root&-vertical-right,
&-root&-inline {
box-shadow: none;
} }
&-sub&-inline { &-sub&-inline {
padding: 0; padding: 0;
border: none; border: 0;
border-radius: 0;
box-shadow: none; box-shadow: none;
border-radius: 0;
& > .@{menu-prefix-cls}-item,
& > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
line-height: @menu-item-height;
height: @menu-item-height;
list-style-type: disc;
list-style-position: inside;
}
& > .@{menuPrefixCls}-item, & > .@{menuPrefixCls}-submenu .@{menuPrefixCls}-submenu-title { & .@{menu-prefix-cls}-item-group-title {
padding-top: 8px; padding-left: 32px;
padding-bottom: 8px;
padding-right: 0;
} }
} }
.effect() { // Disabled state sets text to gray and nukes hover/tab effects
animation-duration: .3s; &-item-disabled,
animation-fill-mode: both; &-submenu-disabled {
transform-origin: 0 0; color: @disabled-color !important;
} cursor: not-allowed;
background: none;
&-open { border-color: transparent !important;
> a {
&-slide-up-enter, &-slide-up-appear { color: @disabled-color !important;
.effect(); pointer-events: none;
opacity: 0;
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
animation-play-state: paused;
}
&-slide-up-leave {
.effect();
opacity: 1;
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
animation-play-state: paused;
}
&-slide-up-enter-active, &-slide-up-appear-active {
.effect();
animation-name: rcMenuOpenSlideUpIn;
animation-play-state: running;
}
&-slide-up-leave-active {
.effect();
animation-name: rcMenuOpenSlideUpOut;
animation-play-state: running;
}
@keyframes rcMenuOpenSlideUpIn {
0% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleY(0);
}
100% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleY(1);
}
}
@keyframes rcMenuOpenSlideUpOut {
0% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleY(1);
}
100% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleY(0);
}
}
&-zoom-enter, &-zoom-appear {
opacity: 0;
.effect();
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
animation-play-state: paused;
}
&-zoom-leave {
.effect();
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
animation-play-state: paused;
}
&-zoom-enter-active, &-zoom-appear-active {
.effect();
animation-name: rcMenuOpenZoomIn;
animation-play-state: running;
}
&-zoom-leave-active {
.effect();
animation-name: rcMenuOpenZoomOut;
animation-play-state: running;
}
@keyframes rcMenuOpenZoomIn {
0% {
opacity: 0;
transform: scale(0, 0);
}
100% {
opacity: 1;
transform: scale(1, 1);
}
}
@keyframes rcMenuOpenZoomOut {
0% {
transform: scale(1, 1);
}
100% {
opacity: 0;
transform: scale(0, 0);
} }
> .@{menu-prefix-cls}-submenu-title {
color: @disabled-color !important;
cursor: not-allowed;
} }
} }
} }
@import './dark';

View File

@ -24,8 +24,8 @@ export default {
popupClassName: PropTypes.any, popupClassName: PropTypes.any,
}, },
data () { data () {
this.aligned = false
return { return {
aligned: false,
destroyPopup: false, destroyPopup: false,
initAlign: false, // mountedalign,this.$el initAlign: false, // mountedalign,this.$el
} }

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const com = pathnameArr[1] || 'button' const com = pathnameArr[1] || 'button'
const demo = pathnameArr[2] || 'index' const demo = pathnameArr[2] || 'index'
return { return {
component: import(`../components/tooltip/demo/${demo}.vue`), component: import(`../components/checkbox/demo/${demo}.vue`),
} }
} }
export default [ export default [