mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2024-12-09 04:31:35 +08:00
refactor(dropdown): new api
This commit is contained in:
parent
c6c96aa375
commit
8fd7d00446
@ -5,6 +5,7 @@ trigger
|
||||
placement
|
||||
cascade
|
||||
size
|
||||
manual-position
|
||||
```
|
||||
# Placeholder
|
||||
# Placeholder
|
||||
|
@ -0,0 +1,77 @@
|
||||
# Manually Positioned
|
||||
```html
|
||||
<div style="width: 200px; height: 200px; background-color: rgba(0, 128, 0, .5);" @contextmenu="handleContextMenu"></div>
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
manually-positioned
|
||||
@select="handleSelect"
|
||||
@blur="handleBlur"
|
||||
:x="x"
|
||||
:y="y"
|
||||
v-model="showDropdown"
|
||||
>
|
||||
<n-dropdown-item name="gatsby">
|
||||
Gatsby
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item name="daisy">
|
||||
Daisy
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item name="nick">
|
||||
Nick
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item name="jordan baker">
|
||||
Jordan Baker
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item name="tom buchanan">
|
||||
Tom Buchanan
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item name="chicken">
|
||||
Chicken
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item name="beef">
|
||||
Beef
|
||||
</n-dropdown-item>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown>
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
methods: {
|
||||
handleSelect (name) {
|
||||
this.showDropdown = false
|
||||
this.$NMessage.info(name)
|
||||
},
|
||||
handleBlur () {
|
||||
this.showDropdown = false
|
||||
},
|
||||
handleContextMenu (e) {
|
||||
e.preventDefault()
|
||||
this.showDropdown = false
|
||||
this.$nextTick().then(() => {
|
||||
this.showDropdown = true
|
||||
this.x = e.clientX
|
||||
this.y = e.clientY
|
||||
})
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showDropdown: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -3,43 +3,85 @@
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
size="medium"
|
||||
:width="160"
|
||||
:submenu-width="160"
|
||||
size="small"
|
||||
:focusable="false"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div>menu</div>
|
||||
<n-button>Small Some</n-button>
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item1
|
||||
<n-dropdown-item name="gatsby">
|
||||
Gatsby
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item2
|
||||
<n-dropdown-item name="daisy">
|
||||
Daisy
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item3
|
||||
<n-dropdown-item name="nick">
|
||||
Nick
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item4
|
||||
<n-dropdown-item name="jordan baker">
|
||||
Jordan Baker
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item5
|
||||
<n-dropdown-item name="tom buchanan">
|
||||
Tom Buchanan
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu2
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item6
|
||||
<n-dropdown-item name="chicken">
|
||||
Chicken
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item7
|
||||
<n-dropdown-item name="beef">
|
||||
Beef
|
||||
</n-dropdown-item>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown>
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
size="medium"
|
||||
:focusable="false"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<n-button>Medium Some</n-button>
|
||||
</template>
|
||||
<n-dropdown-item name="gatsby">
|
||||
Gatsby
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item name="daisy">
|
||||
Daisy
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item name="nick">
|
||||
Nick
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item name="jordan baker">
|
||||
Jordan Baker
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item name="tom buchanan">
|
||||
Tom Buchanan
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item name="chicken">
|
||||
Chicken
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item name="beef">
|
||||
Beef
|
||||
</n-dropdown-item>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown-submenu>
|
||||
@ -48,84 +90,48 @@
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
size="large"
|
||||
:focusable="false"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div>menu</div>
|
||||
<n-button>Large Some</n-button>
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item1
|
||||
<n-dropdown-item name="gatsby">
|
||||
Gatsby
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item2
|
||||
<n-dropdown-item name="daisy">
|
||||
Daisy
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item3
|
||||
<n-dropdown-item name="nick">
|
||||
Nick
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item4
|
||||
<n-dropdown-item name="jordan baker">
|
||||
Jordan Baker
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item5
|
||||
<n-dropdown-item name="tom buchanan">
|
||||
Tom Buchanan
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu2
|
||||
Others
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item6
|
||||
<n-dropdown-item name="chicken">
|
||||
Chicken
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item7
|
||||
</n-dropdown-item>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown>
|
||||
<n-dropdown
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
size="huge"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div>menu</div>
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item1
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item2
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item3
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item4
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-divider />
|
||||
<n-dropdown-item>
|
||||
item5
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-submenu>
|
||||
<template v-slot:activator>
|
||||
submenu2
|
||||
</template>
|
||||
<n-dropdown-item>
|
||||
item6
|
||||
</n-dropdown-item>
|
||||
<n-dropdown-item>
|
||||
item7
|
||||
<n-dropdown-item name="beef">
|
||||
Beef
|
||||
</n-dropdown-item>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown-submenu>
|
||||
</n-dropdown>
|
||||
```
|
||||
```css
|
||||
.n-button {
|
||||
margin: 0 8px 12px 0;
|
||||
}
|
||||
```
|
@ -1,4 +1,4 @@
|
||||
# Basic
|
||||
# Trigger
|
||||
```html
|
||||
<n-dropdown @select="handleSelect" trigger="hover">
|
||||
<template v-slot:activator>
|
||||
@ -13,7 +13,7 @@
|
||||
</n-dropdown-item>
|
||||
</n-dropdown>
|
||||
|
||||
<n-dropdown @select="handleSelect" trigger="click">
|
||||
<n-dropdown @select="handleSelect" trigger="click" :focusable="false">
|
||||
<template v-slot:activator>
|
||||
<n-button>I want to click!</n-button>
|
||||
</template>
|
||||
@ -25,6 +25,19 @@
|
||||
{{ hotel }}
|
||||
</n-dropdown-item>
|
||||
</n-dropdown>
|
||||
|
||||
<n-dropdown @select="handleSelect" trigger="manual" v-model="showDropdown">
|
||||
<template v-slot:activator>
|
||||
<n-button @click="handleClick">Oh! By Myself!</n-button>
|
||||
</template>
|
||||
<n-dropdown-item
|
||||
v-for="hotel in hotels"
|
||||
:key="hotel"
|
||||
:name="hotel.toLowerCase()"
|
||||
>
|
||||
{{ hotel }}
|
||||
</n-dropdown-item>
|
||||
</n-dropdown>
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
@ -32,12 +45,16 @@ export default {
|
||||
return {
|
||||
hotels: [
|
||||
'Marina Bay Sands, Singapore', 'Brown’s Hotel, London', 'Atlantis Bahamas, Nassau', 'The Beverly Hills Hotel, Los Angeles'
|
||||
]
|
||||
],
|
||||
showDropdown: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSelect (name) {
|
||||
this.$NMessage.info(name)
|
||||
},
|
||||
handleClick () {
|
||||
this.showDropdown = !this.showDropdown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,4 +8,5 @@ event
|
||||
placement
|
||||
raw-content
|
||||
width
|
||||
manual-position
|
||||
```
|
28
demo/documentation/components/popover/enUS/manualPosition.md
Normal file
28
demo/documentation/components/popover/enUS/manualPosition.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Manually Positioned
|
||||
```html
|
||||
<div style="width: 200px; height: 200px; background-color: rgba(0, 128, 0, .5);" @click="handleClick"></div>
|
||||
<n-popover trigger="manual" v-model="showPopover" :x="x" :y="y" manually-positioned>
|
||||
666
|
||||
</n-popover>
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
methods: {
|
||||
handleClick(e) {
|
||||
this.showPopover = false
|
||||
this.$nextTick().then(() => {
|
||||
this.showPopover = true
|
||||
this.x = e.clientX
|
||||
this.y = e.clientY
|
||||
})
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showPopover: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -9,7 +9,6 @@ export default {
|
||||
}
|
||||
return defaultSlot[0]
|
||||
} else {
|
||||
console.error(`NBaseContext: default slot is empty`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
export default {
|
||||
name: 'NBasePortal',
|
||||
provide () {
|
||||
return {
|
||||
NBasePortal: this
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.$el.parentElement && !this.elementTransferred) {
|
||||
this.$el.parentElement.removeChild(this.$el)
|
||||
|
@ -49,6 +49,10 @@ export default {
|
||||
submenuMinWidth: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
focusable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -86,7 +90,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.autoFocus) {
|
||||
if (this.autoFocus && this.focusable) {
|
||||
this.$el.focus()
|
||||
}
|
||||
},
|
||||
@ -138,6 +142,7 @@ export default {
|
||||
},
|
||||
handleBlur () {
|
||||
this.controller.hide()
|
||||
this.$emit('blur')
|
||||
},
|
||||
handleMouseEnter () {
|
||||
if (this.NDropdownMenu) {
|
||||
@ -161,9 +166,6 @@ export default {
|
||||
keydown: this.handleKeyDown,
|
||||
mouseenter: this.handleMouseEnter,
|
||||
blur: this.handleBlur
|
||||
},
|
||||
attrs: {
|
||||
tabindex: '0'
|
||||
}
|
||||
}, [
|
||||
h(NBaseSelectOptionCollector, {
|
||||
|
@ -8,7 +8,7 @@ export default {
|
||||
props: {
|
||||
trigger: {
|
||||
validator (value) {
|
||||
return ['click', 'hover'].includes(value)
|
||||
return ['click', 'hover', 'manual'].includes(value)
|
||||
},
|
||||
default: 'click'
|
||||
},
|
||||
@ -49,6 +49,26 @@ export default {
|
||||
submenuWidth: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
manuallyPositioned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
focusable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
@ -64,6 +84,10 @@ export default {
|
||||
width: context.props.width,
|
||||
minWidth: context.props.minWidth,
|
||||
maxWidth: context.props.maxWidth,
|
||||
value: context.props.value,
|
||||
manuallyPositioned: context.props.manuallyPositioned,
|
||||
x: context.props.x,
|
||||
y: context.props.y,
|
||||
arrow: false,
|
||||
raw: true,
|
||||
shadow: false,
|
||||
@ -75,19 +99,25 @@ export default {
|
||||
},
|
||||
default () {
|
||||
return h(NDropdownMenu, {
|
||||
attrs: {
|
||||
tabindex: context.props.focusable ? '0' : '-1'
|
||||
},
|
||||
props: {
|
||||
autoFocus: context.props.autoFocus,
|
||||
size: context.props.size,
|
||||
controller,
|
||||
submenuWidth: context.props.submenuWidth
|
||||
submenuWidth: context.props.submenuWidth,
|
||||
focusable: context.props.focusable
|
||||
},
|
||||
on: {
|
||||
blur: context.listeners.blur || (() => {}),
|
||||
select: context.listeners.select || (() => {})
|
||||
},
|
||||
scopedSlots: context.scopedSlots
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
on: context.listeners
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
manuallyPositioned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detachedContainerClass: {
|
||||
type: String,
|
||||
default: 'n-popover-detached-content-container'
|
||||
@ -67,6 +71,11 @@ export default {
|
||||
clickoutside,
|
||||
mousemoveoutside
|
||||
},
|
||||
inject: {
|
||||
NBasePortal: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
internalActive: false,
|
||||
@ -87,6 +96,9 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
detached () {
|
||||
return this.NBasePortal.elementTransferred
|
||||
},
|
||||
style () {
|
||||
const style = {}
|
||||
if (this.width) {
|
||||
|
@ -68,14 +68,26 @@ export default {
|
||||
detachedContainerClass: {
|
||||
type: String,
|
||||
default: 'n-popover-detached-content-container'
|
||||
},
|
||||
manuallyPositioned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
render (h, context) {
|
||||
const slots = context.scopedSlots
|
||||
const defaultSlot = slots.default && slots.default()
|
||||
const activatorSlot = slots.activator && slots.activator()
|
||||
const activatorSlot = (slots.activator && slots.activator()) || []
|
||||
let activatorVNode = activatorSlot[0]
|
||||
if (!activatorVNode.tag) {
|
||||
if (activatorVNode && !activatorVNode.tag) {
|
||||
activatorVNode = h('span', {
|
||||
staticClass: 'n-popover-text-wrapper'
|
||||
}, [activatorVNode])
|
||||
|
@ -61,6 +61,18 @@ export default {
|
||||
return ['self', 'activator'].includes(value)
|
||||
},
|
||||
default: 'self'
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
manuallyPositioned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -73,6 +85,12 @@ export default {
|
||||
if (newValue) {
|
||||
this.$nextTick().then(this.updatePosition)
|
||||
}
|
||||
},
|
||||
x () {
|
||||
this.$nextTick().then(this.updatePosition)
|
||||
},
|
||||
y () {
|
||||
this.$nextTick().then(this.updatePosition)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -123,21 +141,39 @@ export default {
|
||||
this.trackingElement.setAttribute('n-suggested-transform-origin', 'top left')
|
||||
},
|
||||
updatePosition (el, cb, keepOrigin = false) {
|
||||
// console.log('scroll')
|
||||
if (!this.active && !this.show) return
|
||||
// console.log('update position', el, cb, keepOrigin)
|
||||
// console.log('[placeable.updatePosition]')
|
||||
this._getTrackedElement()
|
||||
if (!this.manuallyPositioned) {
|
||||
this._getTrackedElement()
|
||||
}
|
||||
this._getTrackingElement()
|
||||
if (!this.trackedElement || !this.trackingElement) {
|
||||
console.log('[placeable.updatePosition]: trakedElement or trackingElement not found!')
|
||||
if (this.manuallyPositioned) {
|
||||
if (!this.trackingElement) {
|
||||
console.error('[naive-ui/placeable/updatePosition]: trackingElement not found!')
|
||||
}
|
||||
} else {
|
||||
if (!this.trackedElement || !this.trackingElement) {
|
||||
console.error('[naive-ui/placeable/updatePosition]: trakedElement or trackingElement not found!')
|
||||
}
|
||||
}
|
||||
if (this.positionModeisAbsolute) {
|
||||
this.updatePositionInAbsoluteMode()
|
||||
return
|
||||
}
|
||||
// console.log(activator)
|
||||
const activatorBoundingClientRect = this.trackedElement.getBoundingClientRect()
|
||||
let activatorBoundingClientRect = null
|
||||
if (!this.manuallyPositioned) {
|
||||
activatorBoundingClientRect = this.trackedElement.getBoundingClientRect()
|
||||
} else {
|
||||
activatorBoundingClientRect = {
|
||||
top: this.y,
|
||||
left: this.x,
|
||||
height: 0,
|
||||
width: 0,
|
||||
right: this.x,
|
||||
bottom: this.y
|
||||
}
|
||||
// console.log(activatorBoundingClientRect)
|
||||
}
|
||||
// console.log(activatorBoundingClientRect)
|
||||
// console.log(this.$refs.popoverBody)
|
||||
// debugger
|
||||
@ -146,6 +182,7 @@ export default {
|
||||
// debugger
|
||||
// console.log('scroll', activatorBoundingClientRect, contentBoundingClientRect)
|
||||
const [placementTransform, suggestedTransformOrigin] = calcPlacementTransfrom(this.placement, activatorBoundingClientRect, contentBoundingClientRect)
|
||||
// console.log(placementTransform)
|
||||
this.trackingElement.style.position = 'absolute'
|
||||
this.trackingElement.style.top = placementTransform.top
|
||||
this.trackingElement.style.left = placementTransform.left
|
||||
|
Loading…
Reference in New Issue
Block a user