feat(select): support variadic height option render

This commit is contained in:
07akioni 2021-09-13 01:27:08 +08:00
parent 003f3db2e0
commit cf29465775
14 changed files with 429 additions and 65 deletions

View File

@ -12,6 +12,7 @@
- `n-select` add `on-update:show` prop.
- `n-auto-complete` exports `AutoCompleteOption` and `AutoCompleteGroupOption` types.
- `n-page-header` add `RTL` support.
- `n-select` support variadic height option rendering.
### Fixes

View File

@ -12,6 +12,7 @@
- `n-select` 新增 `on-update:show` 属性
- `n-auto-complete` 导出 `AutoCompleteOption` 以及 `AutoCompleteGroupOption` 类型
- `n-page-header` 添加 `RTL` 支持
- `n-select` 支持可变高度选项渲染
### Fixes

View File

@ -294,6 +294,7 @@ export default defineComponent({
optionCheckColor,
actionTextColor,
optionColorPending,
optionColorActive,
loadingColor,
loadingSize,
[createKey('optionFontSize', size)]: fontSize,
@ -312,6 +313,7 @@ export default defineComponent({
'--group-header-text-color': groupHeaderTextColor,
'--option-check-color': optionCheckColor,
'--option-color-pending': optionColorPending,
'--option-color-active': optionColorActive,
'--option-height': optionHeight,
'--option-opacity-disabled': optionOpacityDisabled,
'--option-text-color': optionTextColor,
@ -404,6 +406,7 @@ export default defineComponent({
paddingBottom={this.padding.bottom}
onResize={this.handleVirtualListResize}
onScroll={this.handleVirtualListScroll}
itemResizable
>
{{
default: ({

View File

@ -149,7 +149,7 @@ export default defineComponent({
onMouseenter={handleMouseEnter}
onMousemove={handleMouseMove}
>
{children}
<div class={`${clsPrefix}-base-select-option__content`}>{children}</div>
</div>
)
return rawNode.render

View File

@ -4,6 +4,7 @@ import fadeInScaleUpTransition from '../../../../_styles/transitions/fade-in-sca
// --loading-color
// --loading-size
export default cB('base-select-menu', `
line-height: 1.5;
outline: none;
z-index: 0;
position: relative;
@ -20,14 +21,22 @@ export default cB('base-select-menu', `
max-height: var(--height);
`),
cB('base-select-option', `
height: var(--option-height);
line-height: var(--option-height);
min-height: var(--option-height);
font-size: var(--option-font-size);
`),
display: flex;
align-items: center;
`, [
cE('content', `
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
`)
]),
cB('base-select-group-header', `
height: var(--option-height);
line-height: var(--option-height);
min-height: var(--option-height);
font-size: .93em;
display: flex;
align-items: center;
`),
cB('base-select-menu-option-wrapper', `
position: relative;
@ -62,44 +71,42 @@ export default cB('base-select-menu', `
cursor: pointer;
position: relative;
padding: var(--option-padding);
white-space: nowrap;
transition:
background-color .3s var(--bezier),
color .3s var(--bezier),
opacity .3s var(--bezier);
text-overflow: ellipsis;
overflow: hidden;
box-sizing: border-box;
color: var(--option-text-color);
opacity: 1;
`, [
c('&:active', {
color: 'var(--option-text-color-pressed)'
}),
cM('grouped', {
paddingLeft: 'calc(var(--option-padding-left) * 1.5)'
}),
cM('selected', {
color: 'var(--option-text-color-active)'
}),
cM('disabled', {
cursor: 'not-allowed'
}, [
cNotM('selected', {
color: 'var(--option-text-color-disabled)'
}),
cM('selected', {
opacity: 'var(--option-opacity-disabled)'
})
c('&:active', `
color: var(--option-text-color-pressed);
`),
cM('grouped', `
padding-left: calc(var(--option-padding-left) * 1.5);
`),
cM('pending', `
background-color: var(--option-color-pending);
`),
cM('selected', `
color: var(--option-text-color-active);
background-color: var(--option-color-active);
`),
cM('disabled', `
cursor: not-allowed;
`, [
cNotM('selected', `
color: var(--option-text-color-disabled);
`),
cM('selected', `
opacity: var(--option-opacity-disabled);
`)
]),
cM('pending', {
backgroundColor: 'var(--option-color-pending)'
}),
cE('check', `
font-size: 14px;
position: absolute;
right: 8px;
top: calc(var(--option-height) / 2 - 7px);
top: calc(50% - 7px);
color: var(--option-check-color);
transition: color .3s var(--bezier);
`, [

View File

@ -1,3 +1,4 @@
import { changeColor } from 'seemly'
import { emptyDark } from '../../../empty/styles'
import { scrollbarDark } from '../../../scrollbar/styles'
import { commonDark } from '../../../_styles/common'
@ -11,7 +12,12 @@ const internalSelectMenuDark: InternalSelectMenuTheme = {
Scrollbar: scrollbarDark,
Empty: emptyDark
},
self
self (vars) {
const { primaryColor } = vars
const commonSelf = self(vars)
commonSelf.optionColorActive = changeColor(primaryColor, { alpha: 0.15 })
return commonSelf
}
}
export default internalSelectMenuDark

View File

@ -4,6 +4,7 @@ import { commonLight } from '../../../_styles/common'
import type { ThemeCommonVars } from '../../../_styles/common'
import commonVariables from './_common'
import { createTheme } from '../../../_mixins'
import { changeColor } from 'seemly'
export const self = (vars: ThemeCommonVars) => {
const {
@ -47,6 +48,7 @@ export const self = (vars: ThemeCommonVars) => {
optionOpacityDisabled: opacityDisabled,
optionCheckColor: primaryColor,
optionColorPending: hoverColor,
optionColorActive: changeColor(primaryColor, { alpha: 0.1 }),
actionTextColor: textColor2,
loadingColor: primaryColor
}

View File

@ -120,9 +120,14 @@ export default defineComponent({
})
const filterablePlaceholderRef = computed(() => {
return props.selectedOption
? props.renderLabel
? props.renderLabel(props.selectedOption as never, true)
: render(props.selectedOption.label, props.selectedOption, true)
? props.renderTag
? props.renderTag({
option: props.selectedOption,
handleClose: () => {}
})
: props.renderLabel
? props.renderLabel(props.selectedOption as never, true)
: render(props.selectedOption.label, props.selectedOption, true)
: props.placeholder
})
const labelRef = computed(() => {
@ -662,7 +667,7 @@ export default defineComponent({
const placeholder =
!this.selected && !this.pattern && !this.isCompositing ? (
<div
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-render-dom`}
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-selection-overlay`}
>
{this.placeholder}
</div>
@ -733,7 +738,7 @@ export default defineComponent({
>
<input
ref="patternInputRef"
class={`${clsPrefix}-base-selection-label__input`}
class={`${clsPrefix}-base-selection-input`}
value={
this.patternInputFocused && this.active ? this.pattern : ''
}
@ -751,17 +756,22 @@ export default defineComponent({
{showPlaceholder ? null : this.patternInputFocused &&
this.active ? null : (
<div
class={`${clsPrefix}-base-selection-label__render-label ${clsPrefix}-base-render-dom`}
class={`${clsPrefix}-base-selection-label__render-label ${clsPrefix}-base-selection-overlay`}
key="input"
>
{renderLabel
? renderLabel(this.selectedOption as SelectBaseOption, true)
: render(this.label, this.selectedOption, true)}
{renderTag
? renderTag({
option: this.selectedOption!,
handleClose: () => {}
})
: renderLabel
? renderLabel(this.selectedOption!, true)
: render(this.label, this.selectedOption, true)}
</div>
)}
{showPlaceholder ? (
<div
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-render-dom`}
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-selection-overlay`}
key="placeholder"
>
{this.filterablePlaceholder}
@ -779,17 +789,24 @@ export default defineComponent({
>
{this.label !== undefined ? (
<div
class={`${clsPrefix}-base-selection-label__input`}
class={`${clsPrefix}-base-selection-input`}
title={getTitleAttribute(this.label)}
key="input"
>
{renderLabel
? renderLabel(this.selectedOption as SelectBaseOption, true)
: render(this.label, this.selectedOption, true)}
<div class={`${clsPrefix}-base-selection-input__content`}>
{renderTag
? renderTag({
option: this.selectedOption as SelectBaseOption,
handleClose: () => {}
})
: renderLabel
? renderLabel(this.selectedOption as SelectBaseOption, true)
: render(this.label, this.selectedOption, true)}
</div>
</div>
) : (
<div
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-render-dom`}
class={`${clsPrefix}-base-selection-placeholder ${clsPrefix}-base-selection-overlay`}
key="placeholder"
>
{this.placeholder}

View File

@ -43,16 +43,12 @@ export default c([
vertical-align: bottom;
border-radius: var(--border-radius);
min-height: var(--height);
line-height: var(--height);
line-height: 1.5;
font-size: var(--font-size);
`, [
cB('base-loading', `
color: var(--loading-color);
`),
cB('base-selection-label', `
height: var(--height);
line-height: var(--height);
`),
cB('base-selection-tags', {
minHeight: 'var(--height)'
}),
@ -85,11 +81,11 @@ export default c([
transition: color .3s var(--bezier);
`)
]),
cB('base-render-dom', `
cB('base-selection-overlay', `
display: flex;
align-items: center;
white-space: nowrap;
overflow: hidden;
height: var(--height);
line-height: var(--height);
pointer-events: none;
position: absolute;
top: 0;
@ -122,7 +118,8 @@ export default c([
background-color .3s var(--bezier);
`),
cB('base-selection-label', `
display: inline-block;
height: var(--height);
display: inline-flex;
width: 100%;
vertical-align: bottom;
cursor: pointer;
@ -136,23 +133,27 @@ export default c([
background-color .3s var(--bezier);
border-radius: inherit;
background-color: var(--color);
align-items: center;
`, [
cE('input', `
cB('base-selection-input', `
line-height: inherit;
outline: none;
cursor: pointer;
box-sizing: border-box;
text-overflow: ellipsis;
overflow: hidden;
border:none;
width: 100%;
white-space: nowrap;
padding: var(--padding-single);
background-color: #0000;
color: var(--text-color);
transition: color .3s var(--bezier);
caret-color: var(--caret-color);
`),
`, [
cE('content', `
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
`)
]),
cE('render-label', `
color: var(--text-color);
`)
@ -193,7 +194,7 @@ export default c([
cursor: not-allowed;
background-color: var(--color-disabled);
`, [
cE('input', `
cB('base-selection-input', `
cursor: not-allowed;
color: var(--text-color-disabled);
`),

View File

@ -24,6 +24,7 @@ fallback-option
max-tag-count
add-tooltip
render-tag
render-person
```
## API

View File

@ -0,0 +1,162 @@
# Select Person
I find in many scenes people want to make select a people picker. Here is an example that shows you how to customize the select.
```html
<n-space vertical>
<n-select
:options="options"
:render-label="renderLabel"
:render-tag="renderSingleSelectTag"
/>
<n-select
:options="options"
:render-label="renderLabel"
:render-tag="renderSingleSelectTag"
filterable
/>
<n-select
multiple
:options="options"
:render-label="renderLabel"
:render-tag="renderMultipleSelectTag"
/>
<n-select
multiple
:options="options"
:render-label="renderLabel"
:render-tag="renderMultipleSelectTag"
filterable
/>
</n-space>
```
```js
import { defineComponent, h } from 'vue'
import { NAvatar, NText, NTag } from 'naive-ui'
export default defineComponent({
setup () {
return {
options: [
{
label: '07akioni',
value: '07akioni'
},
{
label: '08akioni',
value: '08akioni'
},
{
label: '09akioni',
value: '09akioni'
}
],
renderMultipleSelectTag: ({ option, handleClose }) => {
return h(
NTag,
{
style: {
padding: '0 6px 0 4px'
},
round: true,
closable: true,
onClose: (e) => {
e.stopPropagation()
handleClose()
}
},
{
default: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 22,
style: {
marginRight: '4px'
}
}),
option.label
]
)
}
)
},
renderSingleSelectTag: ({ option }) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 24,
style: {
marginRight: '12px'
}
}),
option.label
]
)
},
renderLabel: (option) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 'small'
}),
h(
'div',
{
style: {
marginLeft: '12px',
padding: '4px 0'
}
},
[
h(
NText,
{ depth: 2, tag: 'div' },
{
default: () => option.label
}
),
h(
NText,
{ depth: 3, tag: 'div' },
{
default: () => 'description'
}
)
]
)
]
)
}
}
}
})
```

View File

@ -24,6 +24,7 @@ fallback-option
max-tag-count
add-tooltip
render-tag
render-person
change-debug
placeholder-debug
menu-debug

View File

@ -0,0 +1,162 @@
# 选择人员
我发现很多场景需要把 Select 改为一个人员选择器,这是一个教你如何定制的演示。
```html
<n-space vertical>
<n-select
:options="options"
:render-label="renderLabel"
:render-tag="renderSingleSelectTag"
/>
<n-select
:options="options"
:render-label="renderLabel"
:render-tag="renderSingleSelectTag"
filterable
/>
<n-select
multiple
:options="options"
:render-label="renderLabel"
:render-tag="renderMultipleSelectTag"
/>
<n-select
multiple
:options="options"
:render-label="renderLabel"
:render-tag="renderMultipleSelectTag"
filterable
/>
</n-space>
```
```js
import { defineComponent, h } from 'vue'
import { NAvatar, NText, NTag } from 'naive-ui'
export default defineComponent({
setup () {
return {
options: [
{
label: '07akioni',
value: '07akioni'
},
{
label: '08akioni',
value: '08akioni'
},
{
label: '09akioni',
value: '09akioni'
}
],
renderMultipleSelectTag: ({ option, handleClose }) => {
return h(
NTag,
{
style: {
padding: '0 6px 0 4px'
},
round: true,
closable: true,
onClose: (e) => {
e.stopPropagation()
handleClose()
}
},
{
default: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 22,
style: {
marginRight: '4px'
}
}),
option.label
]
)
}
)
},
renderSingleSelectTag: ({ option }) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 24,
style: {
marginRight: '12px'
}
}),
option.label
]
)
},
renderLabel: (option) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center'
}
},
[
h(NAvatar, {
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
round: true,
size: 'small'
}),
h(
'div',
{
style: {
marginLeft: '12px',
padding: '4px 0'
}
},
[
h(
NText,
{ depth: 2, tag: 'div' },
{
default: () => option.label
}
),
h(
NText,
{ depth: 3, tag: 'div' },
{
default: () => 'description'
}
)
]
)
]
)
}
}
}
})
```

View File

@ -43,9 +43,9 @@ export default cB('tag', `
color .3s var(--bezier),
box-shadow .3s var(--bezier),
opacity .3s var(--bezier);
line-height: var(--height);
height: var(--height);
font-size: var(--font-size);
line-height: 1.5;
height: var(--height);
font-size: var(--font-size);
`, [
cE('border', `
pointer-events: none;