feat(popselect): support class attr (#189)

* feat(popselect): support class attr

* test: update snapshot
This commit is contained in:
07akioni 2021-06-18 22:28:22 +08:00 committed by GitHub
parent 4afacaa2b4
commit dbcf7a2b73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 106 additions and 64 deletions

View File

@ -2,12 +2,12 @@
## Pending ## Pending
- `n-input` add show-password-toggle prop.
### Feats ### Feats
- `n-form`, `n-form-item` enhance show-require-mark propcloses [#171](https://github.com/TuSimple/naive-ui/issues/171) - `n-form`, `n-form-item` enhance show-require-mark propcloses [#171](https://github.com/TuSimple/naive-ui/issues/171)
- `n-dropdown` support class attr, closes [#180](https://github.com/TuSimple/naive-ui/issues/180). - `n-dropdown` support class attr, closes [#180](https://github.com/TuSimple/naive-ui/issues/180).
- `n-input` add `show-password-toggle` prop.
- `n-popselect` support class attr.
### Fixes ### Fixes

View File

@ -2,12 +2,12 @@
## Pending ## Pending
- 为 `n-input` 组件中 password 属性增加查看隐藏功能
### Feats ### Feats
- `n-form`, `n-form-item` 增强 show-require-mark 属性,关闭 [#171](https://github.com/TuSimple/naive-ui/issues/171) - `n-form`, `n-form-item` 增强 show-require-mark 属性,关闭 [#171](https://github.com/TuSimple/naive-ui/issues/171)
- `n-dropdown` 支持 class 属性,关闭 [#180](https://github.com/TuSimple/naive-ui/issues/180) - `n-dropdown` 支持 class 属性,关闭 [#180](https://github.com/TuSimple/naive-ui/issues/180)
- `n-input` 新增 `show-password-toggle` 属性
- `n-popselect` 支持 class 属性
### Fixes ### Fixes

View File

@ -28,3 +28,19 @@
#### 注意事项 #### 注意事项
- `feat(xxx)` 必须是组件,不能加 `n``feat(input)` ✅,`feat(n-input)` ❌ - `feat(xxx)` 必须是组件,不能加 `n``feat(input)` ✅,`feat(n-input)` ❌
## Changelog
- 新增属性
```
- `n-xxx` add xxx prop.
- `n-xxx` 新增 xxx 属性
```
- 修复 Bug
```
- Fix `n-xxx` ...
- 修复 `n-xxx` ...
```

View File

@ -107,6 +107,8 @@ export default defineComponent({
onKeyup: Function as PropType<(e: KeyboardEvent) => void>, onKeyup: Function as PropType<(e: KeyboardEvent) => void>,
onKeydown: Function as PropType<(e: KeyboardEvent) => void>, onKeydown: Function as PropType<(e: KeyboardEvent) => void>,
onTabOut: Function as PropType<() => void>, onTabOut: Function as PropType<() => void>,
onMouseenter: Function as PropType<(e: MouseEvent) => void>,
onMouseleave: Function as PropType<(e: MouseEvent) => void>,
// deprecated // deprecated
onMenuToggleOption: Function as PropType<(value: SelectBaseOption) => void> onMenuToggleOption: Function as PropType<(value: SelectBaseOption) => void>
}, },
@ -378,6 +380,8 @@ export default defineComponent({
onKeyup={this.handleKeyUp} onKeyup={this.handleKeyUp}
onKeydown={this.handleKeyDown} onKeydown={this.handleKeyDown}
onMousedown={this.handleMouseDown} onMousedown={this.handleMouseDown}
onMouseenter={this.onMouseenter}
onMouseleave={this.onMouseleave}
> >
{this.loading ? ( {this.loading ? (
<div class={`${clsPrefix}-base-select-menu__loading`}> <div class={`${clsPrefix}-base-select-menu__loading`}>

View File

@ -309,7 +309,6 @@ export default defineComponent({
padding, padding,
dividerColor, dividerColor,
borderRadius, borderRadius,
boxShadow,
optionOpacityDisabled, optionOpacityDisabled,
[createKey('optionIconSuffixWidth', size)]: optionIconSuffixWidth, [createKey('optionIconSuffixWidth', size)]: optionIconSuffixWidth,
[createKey('optionSuffixWidth', size)]: optionSuffixWidth, [createKey('optionSuffixWidth', size)]: optionSuffixWidth,
@ -324,7 +323,6 @@ export default defineComponent({
'--font-size': fontSize, '--font-size': fontSize,
'--padding': padding, '--padding': padding,
'--border-radius': borderRadius, '--border-radius': borderRadius,
'--box-shadow': boxShadow,
'--option-height': optionHeight, '--option-height': optionHeight,
'--option-prefix-width': optionPrefixWidth, '--option-prefix-width': optionPrefixWidth,
'--option-icon-prefix-width': optionIconPrefixWidth, '--option-icon-prefix-width': optionIconPrefixWidth,
@ -396,8 +394,13 @@ export default defineComponent({
internalRenderBody: renderPopoverBody, internalRenderBody: renderPopoverBody,
onUpdateShow: this.doUpdateShow onUpdateShow: this.doUpdateShow
} }
return h(NPopover, keep(this.$props, popoverPropKeys, popoverProps), { return (
trigger: this.$slots.default <NPopover {...keep(this.$props, popoverPropKeys)} {...popoverProps}>
}) {{
trigger: this.$slots.default,
_: true
}}
</NPopover>
)
} }
}) })

View File

@ -6,7 +6,6 @@ import fadeInScaleUpTransition from '../../../_styles/transitions/fade-in-scale-
// --font-size // --font-size
// --padding // --padding
// --border-radius // --border-radius
// --box-shadow
// --option-height // --option-height
// --option-prefix-width // --option-prefix-width
// --option-icon-prefix-width // --option-icon-prefix-width
@ -25,6 +24,9 @@ import fadeInScaleUpTransition from '../../../_styles/transitions/fade-in-scale-
// --option-icon-size // --option-icon-size
// --option-opacity-disabled // --option-opacity-disabled
// shared with popover
// --box-shadow
export default cB('dropdown-menu', ` export default cB('dropdown-menu', `
transform-origin: inherit; transform-origin: inherit;
padding: var(--padding); padding: var(--padding);

View File

@ -9,7 +9,6 @@ export const self = (vars: ThemeCommonVars) => {
const { const {
primaryColor, primaryColor,
textColor2, textColor2,
boxShadow2,
dividerColor, dividerColor,
hoverColor, hoverColor,
popoverColor, popoverColor,
@ -33,7 +32,6 @@ export const self = (vars: ThemeCommonVars) => {
optionHeightLarge: heightLarge, optionHeightLarge: heightLarge,
optionHeightHuge: heightHuge, optionHeightHuge: heightHuge,
borderRadius, borderRadius,
boxShadow: boxShadow2,
fontSizeSmall, fontSizeSmall,
fontSizeMedium, fontSizeMedium,
fontSizeLarge, fontSizeLarge,

View File

@ -2,7 +2,7 @@
exports[`n-dropdown inverted style 1`] = ` exports[`n-dropdown inverted style 1`] = `
<div <div
class="n-dropdown-menu n-popover n-dropdown" class="n-dropdown-menu n-popover n-popover--shadow n-dropdown"
style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: rgb(0, 20, 40); --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 4px 0; --space: 6px; --space-arrow: 10px; --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --option-color-hover: #18a058; --option-color-active: #18a058; --option-text-color: #BBB; --option-text-color-hover: #FFF; --option-text-color-active: #FFF; --option-text-color-child-active: #FFF; --prefix-color: #BBB; --suffix-color: #BBB; --group-header-text-color: #AAA;" style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: rgb(0, 20, 40); --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 4px 0; --space: 6px; --space-arrow: 10px; --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --option-color-hover: #18a058; --option-color-active: #18a058; --option-text-color: #BBB; --option-text-color-hover: #FFF; --option-text-color-active: #FFF; --option-text-color-child-active: #FFF; --prefix-color: #BBB; --suffix-color: #BBB; --group-header-text-color: #AAA;"
> >
@ -224,7 +224,7 @@ exports[`n-dropdown inverted style 1`] = `
exports[`n-dropdown shows menu after click 1`] = ` exports[`n-dropdown shows menu after click 1`] = `
<div <div
class="n-dropdown-menu n-popover n-dropdown" class="n-dropdown-menu n-popover n-popover--shadow n-dropdown"
style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: #fff; --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 4px 0; --space: 6px; --space-arrow: 10px; --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --option-color-hover: rgb(243, 243, 245); --option-color-active: rgba(24, 160, 88, 0.1); --option-text-color: rgb(51, 54, 57); --option-text-color-hover: rgb(51, 54, 57); --option-text-color-active: #18a058; --option-text-color-child-active: #18a058; --prefix-color: rgb(51, 54, 57); --suffix-color: rgb(51, 54, 57); --group-header-text-color: rgb(158, 164, 170);" style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: #fff; --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 4px 0; --space: 6px; --space-arrow: 10px; --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --option-color-hover: rgb(243, 243, 245); --option-color-active: rgba(24, 160, 88, 0.1); --option-text-color: rgb(51, 54, 57); --option-text-color-hover: rgb(51, 54, 57); --option-text-color-active: #18a058; --option-text-color-child-active: #18a058; --prefix-color: rgb(51, 54, 57); --suffix-color: rgb(51, 54, 57); --group-header-text-color: rgb(158, 164, 170);"
> >

View File

@ -241,9 +241,11 @@ export default defineComponent({
contentNode = renderBody( contentNode = renderBody(
// The popover class and overlap class must exists, they will be used // The popover class and overlap class must exists, they will be used
// to place the body & transition animation. // to place the body & transition animation.
// Shadow class exists for reuse box-shadow.
[ [
`${mergedClsPrefix}-popover`, `${mergedClsPrefix}-popover`,
props.overlap && `${mergedClsPrefix}-popover--overlap` props.overlap && `${mergedClsPrefix}-popover--overlap`,
props.shadow && `${mergedClsPrefix}-popover--shadow`
], ],
bodyRef, bodyRef,
styleRef.value as any, styleRef.value as any,

View File

@ -2,7 +2,7 @@
```html ```html
<n-popselect v-model:value="value" :options="options"> <n-popselect v-model:value="value" :options="options">
<n-tag>{{ value || 'Popselect' }}</n-tag> <n-button>{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -4,7 +4,7 @@ Make single value popselect cancelable.
```html ```html
<n-popselect v-model:value="value" cancelable :options="options"> <n-popselect v-model:value="value" cancelable :options="options">
<n-tag>{{ value || 'Popselect' }}</n-tag> <n-button>{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -4,8 +4,8 @@ Select multiple value in popselect.
```html ```html
<n-popselect v-model:value="value" multiple :options="options"> <n-popselect v-model:value="value" multiple :options="options">
<n-tag <n-button
>{{ (Array.isArray(value) && value.length) ? value : 'Nothing' }}</n-tag >{{ (Array.isArray(value) && value.length) ? value : 'Nothing' }}</n-button
> >
</n-popselect> </n-popselect>
``` ```

View File

@ -2,7 +2,7 @@
```html ```html
<n-popselect v-model:value="value" :options="options" size="medium" scrollable> <n-popselect v-model:value="value" :options="options" size="medium" scrollable>
<n-tag style="margin-right: 8px;">{{ value || 'Popselect' }}</n-tag> <n-button style="margin-right: 8px;">{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -2,10 +2,10 @@
```html ```html
<n-popselect v-model:value="value" :options="options" size="medium"> <n-popselect v-model:value="value" :options="options" size="medium">
<n-tag style="margin-right: 8px;">{{ value || 'Popselect' }}</n-tag> <n-button style="margin-right: 8px;">{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
<n-popselect v-model:value="value" :options="options" size="large"> <n-popselect v-model:value="value" :options="options" size="large">
<n-tag>{{ value || 'Popselect' }}</n-tag> <n-button>{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -1,8 +1,8 @@
# 基础用法 # 基础用法
```html ```html
<n-popselect v-model:value="value" :options="options"> <n-popselect v-model:value="value" :options="options" trigger="click">
<n-tag>{{ value || '弹出选择' }}</n-tag> <n-button>{{ value || '弹出选择' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -4,7 +4,7 @@
```html ```html
<n-popselect v-model:value="value" cancelable :options="options"> <n-popselect v-model:value="value" cancelable :options="options">
<n-tag>{{ value || '弹出选择' }}</n-tag> <n-button>{{ value || '弹出选择' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -4,7 +4,9 @@
```html ```html
<n-popselect v-model:value="value" multiple :options="options"> <n-popselect v-model:value="value" multiple :options="options">
<n-tag>{{ (Array.isArray(value) && value.length) ? value : '没了' }}</n-tag> <n-button
>{{ (Array.isArray(value) && value.length) ? value : '没了' }}</n-button
>
</n-popselect> </n-popselect>
``` ```

View File

@ -2,7 +2,7 @@
```html ```html
<n-popselect v-model:value="value" :options="options" size="medium" scrollable> <n-popselect v-model:value="value" :options="options" size="medium" scrollable>
<n-tag style="margin-right: 8px;">{{ value || 'Popselect' }}</n-tag> <n-button style="margin-right: 8px;">{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -2,10 +2,10 @@
```html ```html
<n-popselect v-model:value="value" :options="options" size="medium"> <n-popselect v-model:value="value" :options="options" size="medium">
<n-tag style="margin-right: 8px;">{{ value || 'Popselect' }}</n-tag> <n-button style="margin-right: 8px;">{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
<n-popselect v-model:value="value" :options="options" size="large"> <n-popselect v-model:value="value" :options="options" size="large">
<n-tag>{{ value || 'Popselect' }}</n-tag> <n-button>{{ value || 'Popselect' }}</n-button>
</n-popselect> </n-popselect>
``` ```

View File

@ -1,6 +1,7 @@
import { h, ref, provide, defineComponent, PropType } from 'vue' import { h, ref, provide, defineComponent, PropType, mergeProps } from 'vue'
import { NPopover } from '../../popover' import { NPopover } from '../../popover'
import { popoverBaseProps } from '../../popover/src/Popover' import { popoverBaseProps } from '../../popover/src/Popover'
import type { PopoverInternalProps } from '../../popover/src/Popover'
import type { PopoverInst, PopoverTrigger } from '../../popover' import type { PopoverInst, PopoverTrigger } from '../../popover'
import NPopselectPanel, { panelPropKeys, panelProps } from './PopselectPanel' import NPopselectPanel, { panelPropKeys, panelProps } from './PopselectPanel'
import { omit, keep } from '../../_utils' import { omit, keep } from '../../_utils'
@ -14,16 +15,11 @@ import { popselectInjectionKey } from './interface'
const popselectProps = { const popselectProps = {
...(useTheme.props as ThemeProps<PopselectTheme>), ...(useTheme.props as ThemeProps<PopselectTheme>),
...popoverBaseProps, ...popoverBaseProps,
// eslint-disable-next-line vue/require-prop-types
trigger: { trigger: {
type: String as PropType<PopoverTrigger>, type: String as PropType<PopoverTrigger>,
default: 'hover' default: 'hover'
}, },
// eslint-disable-next-line vue/require-prop-types showArrow: Boolean,
showArrow: {
type: Boolean,
default: false
},
...panelProps ...panelProps
} }
@ -58,22 +54,47 @@ export default defineComponent({
} }
}, },
render () { render () {
const { mergedTheme } = this const { mergedTheme, $attrs } = this
return h( const popoverProps: PopoverInternalProps & { ref: string } = {
NPopover, theme: mergedTheme.peers.Popover,
omit(this.$props, panelPropKeys, { themeOverrides: mergedTheme.peerOverrides.Popover,
padded: false, ref: 'popoverInstRef',
ref: 'popoverInstRef', internalRenderBody: (
internalExtraClass: 'popselect', className,
theme: mergedTheme.peers.Popover, ref,
themeOverrides: mergedTheme.peerOverrides.Popover style,
}), onMouseenter,
{ onMouseleave
trigger: this.$slots.default, ) => {
default: () => { return (
return h(NPopselectPanel, keep(this.$props, panelPropKeys)) <NPopselectPanel
} {...mergeProps($attrs, {
class: className,
style
})}
{...keep(this.$props, panelPropKeys)}
ref={
((inst: { $el: HTMLElement | null } | null) => {
if (inst) {
ref.value = inst.$el
} else {
ref.value = null
}
}) as any
}
onMouseenter={onMouseenter}
onMouseleave={onMouseleave}
/>
)
} }
}
return (
<NPopover {...omit(this.$props, panelPropKeys)} {...popoverProps}>
{{
trigger: this.$slots.default,
_: true
}}
</NPopover>
) )
} }
}) })

View File

@ -28,18 +28,12 @@ import { tmOptions } from '../../select/src/utils'
import { useConfig } from '../../_mixins' import { useConfig } from '../../_mixins'
export const panelProps = { export const panelProps = {
multiple: { multiple: Boolean,
type: Boolean,
default: false
},
value: { value: {
type: [String, Number, Array] as PropType<Value | null>, type: [String, Number, Array] as PropType<Value | null>,
default: null default: null
}, },
cancelable: { cancelable: Boolean,
type: Boolean,
default: false
},
width: [Number, String] as PropType<string | number>, width: [Number, String] as PropType<string | number>,
options: { options: {
type: Array as PropType<SelectMixedOption[]>, type: Array as PropType<SelectMixedOption[]>,
@ -49,13 +43,11 @@ export const panelProps = {
type: String as PropType<PopselectSize>, type: String as PropType<PopselectSize>,
default: 'medium' default: 'medium'
}, },
scrollable: { scrollable: Boolean,
type: Boolean,
default: false
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>, 'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>, onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
onMouseenter: Function as PropType<(e: MouseEvent) => void>,
onMouseleave: Function as PropType<(e: MouseEvent) => void>,
// deprecated // deprecated
onChange: { onChange: {
type: [Function, Array] as PropType<MaybeArray<OnUpdateValue> | undefined>, type: [Function, Array] as PropType<MaybeArray<OnUpdateValue> | undefined>,
@ -155,6 +147,8 @@ export default defineComponent({
virtualScroll={false} virtualScroll={false}
scrollable={this.scrollable} scrollable={this.scrollable}
onMenuToggleOption={this.handleMenuToggleOption} onMenuToggleOption={this.handleMenuToggleOption}
onMouseenter={this.onMouseenter}
onMouseleave={this.onMouseenter}
/> />
) )
} }