This commit is contained in:
songwanli2025@163.com 2020-04-29 11:04:16 +08:00
commit 5f6caeb537
40 changed files with 695 additions and 179 deletions

View File

@ -1,9 +1,26 @@
# CHANGELOG
## 1.0.10 (2020-04-28)
### Features
- Add `arrow-placement` prop on `n-collapse`.
- Add `arrow` slot on `n-collapsed-item`.
### Fixes
- Fix the problem that detachable components detached in wrong place when nested like `modal > drawer > component`.
## 1.0.9 (2020-04-23)
### Features
- Add `autofocus` prop on `n-input`.
- Add `closable` option on `NMessage`.
### Fixes
- Fix the problem that the default value of `n-tag` `closable` is set to `true`.
- Fix the problem that `n-data-table` can't use all `pagination`'s props.
- Fix the problem that `n-pagination`'s `on-page-size-change` prop doesn't work.
## 1.0.8 (2020-04-22)
### Features
- Add `n-dynamic-tags`.
- Add `tableHeaderOverlayBackgroundColor` & `inputOverlayBackgroundColor` to `styleScheme`
## 1.0.7 (2020-04-10)
### Features
- Add `filter-option-value` prop for `n-data-table`'s `column` to better deal with single filter mode.

View File

@ -1,4 +1,20 @@
# CHANGELOG
## 1.0.10 (2020-04-28)
### Features
- 为 `n-collapse` 增加了 `arrow-placement` 属性
- 为 `n-collapsed-item` 增加了`arrow` slot
### Fixes
- 解决了可卸载组件在嵌套成 `modal > drawer > component` 样子的时候会被卸载到错误位置的问题
## 1.0.9 (2020-04-23)
### Features
- 为 `n-input` 增加了 `autofocus` 选项
- 为 `NMessage` 增加了 `closable` 选项
### Fixes
- 解决了 `n-tag` `closable` 默认值被设为 `true` 的问题
- 解决了 `n-data-table` 不能使用全部 `pagination` prop 的问题
- 解决了 `n-pagination` `on-page-size-change` 不生效的问题
## 1.0.8 (2020-04-22)
### Features
- 增加 `n-dynamic-tags` 组件.

View File

@ -0,0 +1,27 @@
# Arrow Placement
Use `arrow-placement` to set the placement of arrow.
```html
<n-collapse
v-model="activeNames"
arrow-placement="right"
>
<n-collapse-item title="right" name="1">
<div>good</div>
</n-collapse-item>
<n-collapse-item title="right" name="2">
<div>nice</div>
</n-collapse-item>
<n-collapse-item title="right" name="3">
<div>very good</div>
</n-collapse-item>
</n-collapse>
```
```js
export default {
data() {
return {
activeNames: []
}
}
}
```

View File

@ -3,6 +3,7 @@ I saw it appears in many side control panels.
## Demos
```demo
basic
arrow-placement
accordion
nested
item-header-click
@ -16,14 +17,16 @@ item-header-click
### Collapse
|Name|Type|Default|Description|
|-|-|-|-|
|theme|`'light' \| 'dark'`|`null`||
|expanded-names|`Array`|`null`||
|accordion|`boolean`|`false`||
|arrow-placement|`'left' \| 'right'`|`'left'`||
|expanded-names|`Array<string \| number>`|`null`||
|theme|`'light' \| 'dark'`|`null`||
### Collapse Item
|Name|Type|Default|Description|
|-|-|-|-|
|title|`string \| number`|`null`||
|title|`string`|`null`||
|name|`string \| number`||**required**|
## Slots
@ -37,6 +40,7 @@ item-header-click
|-|-|-|
|default|`()`||
|header|`()`||
|arrow|`({ collapsed: boolean })`||
## Event
### Collapse Event

View File

@ -0,0 +1,27 @@
# 箭头位置
使用 `arrow-placement` 来设定箭头的位置。
```html
<n-collapse
v-model="activeNames"
arrow-placement="right"
>
<n-collapse-item title="青铜" name="1">
<div>可以</div>
</n-collapse-item>
<n-collapse-item title="白银" name="2">
<div>很好</div>
</n-collapse-item>
<n-collapse-item title="黄金" name="3">
<div>真棒</div>
</n-collapse-item>
</n-collapse>
```
```js
export default {
data() {
return {
activeNames: []
}
}
}
```

View File

@ -3,6 +3,7 @@
## 演示
```demo
basic
arrow-placement
accordion
nested
item-header-click
@ -16,15 +17,17 @@ item-header-click
### Collapse Props
|名称|类型|默认值|说明|
|-|-|-|-|
|theme|`'light' \| 'dark'`|`null`||
|expanded-names|`Array`|`null`||
|accordion|`boolean`|`false`||
|arrow-placement|`'left' \| 'right'`|`'left'`||
|expanded-names|`Array<string \| number>`|`null`||
|theme|`'light' \| 'dark'`|`null`||
### Collapse Item Props
|名称|类型|默认值|说明|
|-|-|-|-|
|title|`string \| number`|`null`||
|name|`string \| number`||**必需**|
|title|`string`|`null`||
## Slots
### Collapse Slots
@ -37,6 +40,7 @@ item-header-click
|-|-|-|
|default|`()`||
|header|`()`||
|arrow|`({ collapsed: boolean })`||
## Event
### Collapse Event

View File

@ -1,5 +1,4 @@
# Controlled Pagination
```html
<n-data-table
ref="table"
@ -22,49 +21,16 @@ const columns = [
{
title: 'Address',
key: 'address'
},
{
title: 'Tags',
key: 'tags',
render (h, row) {
const tags = row.tags.map(tagKey => {
return (
<n-tag
style='margin-right:5px'
type={tagKey.length > 5 ? 'warning' : 'default'}
>
{tagKey}
</n-tag>
)
})
return tags
}
}
]
const data = [
{
key: 0,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer']
},
{
key: 1,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser']
},
{
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher']
}
]
const data = Array.apply(null, { length: 46 }).map((_, index) => ({
key: index,
name: `Edward King ${index}`,
age: 32,
address: `London, Park Lane no. ${index}`
}))
export default {
data() {
@ -73,15 +39,16 @@ export default {
columns,
pagination: {
page: 2,
pageCount: data.length,
pageSize: 1,
pageSize: 5,
showSizePicker: true,
pageSizes: [3, 5, 7],
onChange: page => {
this.pagination.page = page
},
onPageSizeChange: pageSize => {
this.pagination.pageSize = pageSize
}
}
}
},
methods: {
}
}
```
}

View File

@ -22,49 +22,16 @@ const columns = [
{
title: 'Address',
key: 'address'
},
{
title: 'Tags',
key: 'tags',
render (h, row) {
const tags = row.tags.map(tagKey => {
return (
<n-tag
style='margin-right:5px'
type={tagKey.length > 5 ? 'warning' : 'default'}
>
{tagKey}
</n-tag>
)
})
return tags
}
}
]
const data = [
{
key: 0,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer']
},
{
key: 1,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser']
},
{
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher']
}
]
const data = Array.apply(null, { length: 46 }).map((_, index) => ({
key: index,
name: `Edward King ${index}`,
age: 32,
address: `London, Park Lane no. ${index}`
}))
export default {
data() {
@ -73,15 +40,17 @@ export default {
columns,
pagination: {
page: 2,
pageCount: data.length,
pageSize: 1,
pageSize: 5,
showSizePicker: true,
pageSizes: [3, 5, 7],
onChange: page => {
this.pagination.page = page
},
onPageSizeChange: pageSize => {
this.pagination.pageSize = pageSize
}
}
}
},
methods: {
}
}
```

View File

@ -78,7 +78,12 @@ Accept all props from form-item & [Col](n-row#Col-Props)
About AsyncValidatorOptions, see <n-a href="https://github.com/yiminghe/async-validator">async-validator</n-a>.
## Slots
### Form, Form Item, Form Item Row, Form Item Col Methods
### Form, Form Item, Form Item Row, Form Item Col Slots
|Name|Parameters|Description|
|-|-|-|
|default|`()`||
|default|`()`||
### Form Item, Form Item Row, Form Item Col Slots
|Name|Parameters|Description|
|-|-|-|
|label|`()`||

View File

@ -78,7 +78,12 @@ validator-debug
关于 AsyncValidatorOptions参考 <n-a href="https://github.com/yiminghe/async-validator">async-validator</n-a>
## Slots
### Form, Form Item, Form Item Row, Form Item Col Methods
### Form, Form Item, Form Item Row, Form Item Col Slots
|名称|参数|说明|
|-|-|-|
|default|`()`||
|default|`()`||
### Form Item, Form Item Row, Form Item Col Slots
|名称|参数|说明|
|-|-|-|
|label|`()`||

View File

@ -41,6 +41,7 @@ passively-activated
|seperator|`string`|`null`|The seperator bewteen pairwise inputs.|
|placeholder|`string \| [string, string]`|`null`|Placeholder of input. When `pair` is `true`, placeholder is an array.|
|passively-activated|`boolean`|`false`||
|autofocus|`boolean`|`false`||
## Slots
### Input Slots

View File

@ -41,6 +41,8 @@ passively-activated
|seperator|`string`|`null`|成对的值中间的分隔符|
|placeholder|`string \| [string, string]`|`null`|文本输入的占位符。如果是 `pair``true``placeholder`是一个数组|
|passively-activated|`boolean`|`false`||
|autofocus|`boolean`|`false`||
## Slots
### Input Slots

View File

@ -0,0 +1,23 @@
# Closable
Set `closable` to make message closable by a click.
```html
<n-button @click="emitInfo">
Open a Message
</n-button>
```
```js
export default {
methods: {
emitInfo() {
this.$NMessage.success(
"I don't know why nobody told you how to unfold your love",
{
closable: true,
duration: 5000
}
)
}
}
}
```

View File

@ -5,6 +5,7 @@ Oracle from the top(always) of the browser.
basic
icon
timing
closable
modify-content
manually-close
about-theme
@ -26,6 +27,7 @@ about-theme
|content|`string \|(() => VNode \| Array<VNode>)`|Can be a render function|
|icon|`() => VNode`|Can be a render function|
|theme|`'light' \| 'dark'`||
|closable|`boolean`||
|onHide|`function`||
|onAfterHide|`function`||
@ -36,6 +38,7 @@ about-theme
|content|`string \| (() => VNode \| Array<VNode>)`|Can be a render function|
|icon|`string \| (() => VNode)`|Can be a render function|
|type|`'info' \| 'success' \| 'warning' \| 'error' \| 'loading'`||
|closable|`boolean`||
|onHide|`function`||
|onAfterHide|`function`||

View File

@ -0,0 +1,23 @@
# 可关闭
设定 `closable` 使 Message 可以通过点击关闭。
```html
<n-button @click="emitInfo">
打开信息
</n-button>
```
```js
export default {
methods: {
emitInfo() {
this.$NMessage.info(
"I don't know why nobody told you how to unfold your love",
{
closable: true,
duration: 5000
}
)
}
}
}
```

View File

@ -5,6 +5,7 @@
basic
icon
timing
closable
modify-content
manually-close
about-theme
@ -26,6 +27,7 @@ about-theme
|content|`string \| (() => VNode \| Array<VNode>)`|可以是 render 函数|
|icon|`() => VNode`|可以是 render 函数|
|theme|`'light' \| 'dark'`||
|closable|`boolean`||
|onHide|`function`||
|onAfterHide|`function`||
@ -36,6 +38,7 @@ about-theme
|content|`string \| (() => VNode \| Array<VNode>)`|可以是 render 函数|
|icon|`string \| (() => VNode)`|可以是 render 函数|
|type|`'info' \| 'success' \| 'warning' \| 'error' \| 'loading'`||
|closable|`boolean`||
|onHide|`function`||
|onAfterHide|`function`||

View File

@ -0,0 +1,255 @@
# Drawer Debug
```html
<n-button @click="modalActive = !modalActive">Toggle</n-button>
<n-modal
title="Dark Modal Debug"
preset="card"
v-model="modalActive"
:overlay-style="{ marginTop: '24px', marginBottom: '24px', width: '800px' }"
>
<n-button @click="drawerActive = !drawerActive">Open Drawer</n-button>
<n-drawer v-model="drawerActive">
<n-radio-group v-model="size" name="top-size" style="margin-bottom: 12px;">
<n-radio-button value="small"></n-radio-button>
<n-radio-button value="medium" ></n-radio-button>
<n-radio-button value="large"></n-radio-button>
</n-radio-group>
<n-form
:model="model"
:rules="rules"
:size="size"
ref="form"
label-placement="top"
>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Input" path="inputValue">
<n-input placeholder="Input" v-model="model.inputValue" />
</n-form-item-col :span="12">
<n-form-item-col :span="12" label="Textarea" path="textareaValue">
<n-input placeholder="Textarea" v-model="model.textareaValue" type="textarea"
:autosize="{
minRows: 3,
maxRows: 5
}"
/>
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Select" path="selectValue">
<n-select placeholder="Select" :options="generalOptions" v-model="model.selectValue"/>
</n-form-item-col>
<n-form-item-col :span="12" label="Multiple Select" path="multipleSelectValue">
<n-select placeholder="Select" :options="generalOptions" v-model="model.multipleSelectValue" multiple/>
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Datetime" path="datetimeValue">
<n-date-picker type="datetime" v-model="model.datetimeValue"/>
</n-form-item-col>
<n-form-item-col :span="12" label="Switch" path="switchValue">
<n-switch v-model="model.switchValue" />
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Checkbox Group" path="checkboxGroupValue">
<n-checkbox-group v-model="model.checkboxGroupValue">
<n-checkbox value="Option 1">Option 1</n-checkbox>
<n-checkbox value="Option 2">Option 2</n-checkbox>
<n-checkbox value="Option 3">Option 3</n-checkbox>
</n-checkbox-group>
</n-form-item-col>
<n-form-item-col :span="12" label="Radio Group" path="radioGroupValue">
<n-radio-group v-model="model.radioGroupValue" name="radiogroup1">
<n-radio value="Radio 1">Radio 1</n-radio>
<n-radio value="Radio 2">Radio 2</n-radio>
<n-radio value="Radio 3">Radio 3</n-radio>
</n-radio-group>
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Radio Button Group" path="radioGroupValue">
<n-radio-group v-model="model.radioGroupValue" name="radiogroup2">
<n-radio-button value="Radio 1">Radio 1</n-radio-button>
<n-radio-button value="Radio 2">Radio 2</n-radio-button>
<n-radio-button value="Radio 3">Radio 3</n-radio-button>
</n-radio-group>
</n-form-item-col>
<n-form-item-col :span="12" label="Input Number" path="inputNumberValue">
<n-input-number v-model="model.inputNumberValue"/>
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="12" label="Time Picker" path="timePickerValue">
<n-time-picker v-model="model.timePickerValue" />
</n-form-item-col>
<n-form-item-col :span="12" label="Slider" path="sliderValue">
<n-slider v-model="model.sliderValue" :step="5"/>
</n-form-item-col>
</n-row>
<n-row :gutter="24">
<n-form-item-col :span="14" label="Transfer" path="transferValue">
<n-transfer
style="width: 100%;"
v-model="model.transferValue"
:options="generalOptions"
/>
</n-form-item-col>
<n-form-item-col :span="5" label="Nested Path" path="nestedValue.path1">
<n-cascader placeholder="Nested Path 1" v-model="model.nestedValue.path1" :options="cascaderOptions"/>
</n-form-item-col>
<n-form-item-col :span="5" path="nestedValue.path2">
<n-select placeholder="Nested Path 2" :options="generalOptions" v-model="model.nestedValue.path2"/>
</n-form-item-col>
</n-row>
<n-row>
<n-col :span="24">
<div style="display: flex; justify-content: flex-end;">
<n-button @click="handleValidateButtonClick" round type="primary">验证</n-button>
</div>
</n-col>
</n-row>
</n-form>
</n-drawer>
</n-modal>
```
```js
export default {
data () {
return {
drawerActive: false,
modalActive: false,
size: 'medium',
model: {
inputValue: null,
textareaValue: null,
selectValue: null,
multipleSelectValue: null,
datetimeValue: null,
nestedValue: {
path1: null,
path2: null
},
switchValue: false,
checkboxGroupValue: null,
radioGroupValue: null,
radioButtonGroupValue: null,
inputNumberValue: null,
timePickerValue: null,
sliderValue: 0,
transferValue: null
},
generalOptions: [
'groode',
'veli good',
'emazing',
'lidiculous'
].map(v => ({
label: v,
value: v
})),
cascaderOptions: [
{
label: 'groode',
value: 'groode',
children: [
{
label: 'veli good',
value: 'veli good'
}
]
}
],
rules: {
inputValue: {
required: true,
trigger: ['blur', 'input'],
message: '请输入 inputValue'
},
textareaValue: {
required: true,
trigger: ['blur', 'input'],
message: '请输入 textareaValue'
},
selectValue: {
required: true,
trigger: ['blur', 'change'],
message: '请选择 selectValue'
},
multipleSelectValue: {
type: 'array',
required: true,
trigger: ['blur', 'change'],
message: '请选择 multipleSelectValue'
},
datetimeValue: {
type: 'number',
required: true,
trigger: ['blur', 'change'],
message: '请输入 datetimeValue'
},
nestedValue: {
path1: {
required: true,
trigger: ['blur', 'input'],
message: '请输入 nestedValue.path1'
},
path2: {
required: true,
trigger: ['blur', 'change'],
message: '请输入 nestedValue.path2'
}
},
checkboxGroupValue: {
type: 'array',
required: true,
trigger: 'change',
message: '请选择 checkboxGroupValue'
},
radioGroupValue: {
required: true,
trigger: 'change',
message: '请选择 radioGroupValue'
},
radioButtonGroupValue: {
required: true,
trigger: 'change',
message: '请选择 radioButtonGroupValue'
},
inputNumberValue: {
type: 'number',
required: true,
trigger: ['blur', 'change'],
message: '请输入 inputNumberValue'
},
timePickerValue: {
type: 'number',
required: true,
trigger: ['blur', 'change'],
message: '请输入 timePickerValue'
},
sliderValue: 0,
transferValue: {
type: 'array',
required: true,
trigger: 'change',
message: '请输入 transferValue'
}
}
}
},
methods: {
handleValidateButtonClick (e) {
e.preventDefault()
this.$refs.form.validate(errors => {
if (!errors) {
this.$NMessage.success('验证成功')
} else {
console.log(errors)
this.$NMessage.error('验证失败')
}
})
}
}
}
```

View File

@ -13,6 +13,7 @@ dark1-debug
dark2-debug
dark3-debug
dark4-debug
drawer-debug
```
## V-model
|Prop|Event|

View File

@ -31,7 +31,7 @@
>
<n-tab-pane
name="signin"
label="登"
label="登"
>
<n-form>
<n-form-item-row label="用户名">
@ -41,7 +41,7 @@
<n-input />
</n-form-item-row>
</n-form>
<n-button type="primary" block></n-button>
<n-button type="primary" block></n-button>
</n-tab-pane>
<n-tab-pane
name="signup"

View File

@ -32,7 +32,7 @@
>
<n-tab-pane
name="signin"
label="登"
label="登"
>
<n-form>
<n-form-item-row label="用户名">
@ -42,7 +42,7 @@
<n-input />
</n-form-item-row>
</n-form>
<n-button type="primary" block></n-button>
<n-button type="primary" block></n-button>
</n-tab-pane>
<n-tab-pane
name="signup"

View File

@ -1,6 +1,6 @@
{
"name": "naive-ui",
"version": "1.0.8",
"version": "1.0.10",
"description": "A Vue UI Framework. Caring About Styles, Themed, Batteries Included.",
"main": "lib/index.js",
"module": "es/index.js",

View File

@ -23,6 +23,12 @@ export default {
type: [Array, String],
default: null
},
arrowPlacement: {
validator (value) {
return ['left', 'right'].includes(value)
},
default: 'left'
},
accordion: {
type: Boolean,
default: false

View File

@ -2,25 +2,34 @@
<div
class="n-collapse-item"
:class="{
'n-collapse-item--active': !collapse,
'n-collapse-item--active': !collapsed,
[`n-collapse-item--${arrowPlacement}-arrow-placement`]: true
}"
>
<div
class="n-collapse-item__header"
:class="{
'n-collapse-item__header--active': !collapse
'n-collapse-item__header--active': !collapsed
}"
@click="handleClick"
>
<n-icon type="ios-arrow-forward">
<ios-arrow-forward />
</n-icon><slot name="header">
<slot v-if="arrowPlacement === 'right'" name="header">
{{ title }}
</slot>
<div class="n-collapse-item-arrow">
<slot name="arrow" :collapsed="collapsed">
<n-icon type="ios-arrow-forward">
<ios-arrow-forward />
</n-icon>
</slot>
</div>
<slot v-if="arrowPlacement === 'left'" name="header">
{{ title }}
</slot>
</div>
<fade-in-height-expand-transition>
<div
v-if="!collapse"
v-if="!collapsed"
class="n-collapse-item__content-wrapper"
>
<div
@ -64,7 +73,10 @@ export default {
}
},
computed: {
collapse () {
arrowPlacement () {
return this.NCollapse.arrowPlacement
},
collapsed () {
const NCollapse = this.NCollapse
if (NCollapse && Array.isArray(NCollapse.expandedNames)) {
const itemName = this.name
@ -77,7 +89,7 @@ export default {
handleClick (e) {
const NCollapse = this.NCollapse
if (NCollapse) {
NCollapse.toggleItem(this.collapse, this.name, e)
NCollapse.toggleItem(this.collapsed, this.name, e)
}
}
}

View File

@ -48,7 +48,10 @@
:theme="syntheticTheme"
:page="syntheticPagination.page"
:page-count="syntheticPagination.pageCount"
:page-size="syntheticPagination.pageSize"
:page-slot="pagination.pageSlot"
:page-sizes="pagination.pageSizes"
:show-size-picker="pagination.showSizePicker"
:show-quick-jumper="!!pagination.showQuickJumper"
:disabled="!!pagination.disabled"
:on-change="syntheticOnPageChange"
@ -371,11 +374,11 @@ export default {
this.pagination.onPageSizeChange && this.pagination.onPageSizeChange(pageSize)
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.internalPageSize = pageSize
this.$emit('change', {
sorter: createShallowClonedObject(this.syntheticActiveSorter),
pagination: createShallowClonedObject(this.syntheticPagination),
filters: createShallowClonedObject(this.syntheticActiveFilters)
})
// this.$emit('change', {
// sorter: createShallowClonedObject(this.syntheticActiveSorter),
// pagination: createShallowClonedObject(this.syntheticPagination),
// filters: createShallowClonedObject(this.syntheticActiveFilters)
// })
this.$emit('page-size-change')
}
},

View File

@ -38,6 +38,7 @@
:class="{
'n-input__textarea--autosize': autosize
}"
:autofocus="autofocus"
:rows="rows"
:placeholder="placeholder"
:value="value"
@ -64,6 +65,7 @@
:minlength="minlength"
:value="pair ? (value && value[0]) : value"
:readonly="readonly"
:autofocus="autofocus"
@blur="handleInputBlur"
@focus="handleInputFocus"
@input="handleInput($event, 0)"
@ -249,6 +251,10 @@ export default {
deactivateOnEnter: {
type: Boolean,
default: false
},
autofocus: {
type: Boolean,
default: false
}
},
data () {

View File

@ -4,6 +4,7 @@ import mdCheckmarkCircle from '../../_icons/md-checkmark-circle'
import mdAlert from '../../_icons/md-alert'
import mdInformationCircle from '../../_icons/md-information-circle'
import mdCloseCircle from '../../_icons/md-close-circle'
import mdClose from '../../_icons/md-close'
import NBaseLoading from '../../_base/Loading'
import IconSwitchTransition from '../../_transition/IconSwitchTransition'
import render from '../../_utils/vue/render'
@ -25,11 +26,20 @@ export default {
type: [String, Function],
default: null
},
closable: {
type: Boolean,
default: false
},
theme: {
type: String,
default: null
}
},
methods: {
handleCloseClick () {
this.$emit('close')
}
},
render (h) {
let icon = null
if (this.icon) {
@ -63,6 +73,7 @@ export default {
return h('div', {
staticClass: 'n-message',
class: {
'n-message--closable': this.closable,
[`n-message--${this.type}-type`]: true,
[`n-${this.theme}-theme`]: this.theme
}
@ -88,7 +99,20 @@ export default {
render: this.content
}
})
])
]),
this.closable
? h('div', {
staticClass: 'n-message__close'
}, [
h(NIcon, {
nativeOn: {
click: this.handleCloseClick
}
}, [
h(mdClose)
])
])
: null
])
}
}

View File

@ -14,12 +14,14 @@ export default {
},
data () {
return {
timerId: null,
active: true,
inheritedTheme: null,
theme: null,
content: null,
type: null,
icon: null,
closable: false,
onHide: () => {},
onAfterHide: () => {}
}
@ -31,14 +33,20 @@ export default {
},
mounted () {
if (this.duration) {
window.setTimeout(this.hide, this.duration)
this.timerId = window.setTimeout(this.hide, this.duration)
}
},
methods: {
hide () {
this.active = false
if (this.timerId) {
window.clearTimeout(this.timerId)
}
this.onHide()
},
handleClose () {
this.hide()
},
deactivate () {
this.hide()
},
@ -61,11 +69,15 @@ export default {
[
this.active
? h(NMessage, {
on: {
close: this.handleClose
},
props: {
theme: this.syntheticTheme,
content: this.content,
type: this.type,
icon: this.icon
icon: this.icon,
closable: this.closable
}
}) : null
]

View File

@ -50,6 +50,7 @@ function updateMessage (instance, content, option) {
instance.type = option.type
instance.content = content
instance.theme = option.theme
instance.closable = option.closable
instance.inheritedTheme = option.inheritedTheme
}

View File

@ -97,6 +97,7 @@ document.documentElement.addEventListener('click', (e) => {
}, true)
export default {
name: 'NModalContent',
components: {
NScrollbar,
NConfirm,

View File

@ -87,7 +87,7 @@
:options="pageSizeOptions"
:value="pageSize"
:disabled="disabled"
@input="handleSizePickerInput"
@change="handleSizePickerChange"
/>
</div>
</template>
@ -243,7 +243,7 @@ export default {
const page = Math.max(this.page - (this.pageSlot - 4), 1)
this.changeCurrentPage(page)
},
handleSizePickerInput (value) {
handleSizePickerChange (value) {
this.changePageSize(value)
},
handleQuickJumperKeyUp (e) {

View File

@ -18,11 +18,12 @@
v-if="inputVisible"
ref="tagInput"
v-model="inputValue"
:force-focus="inputForceFocused"
:theme="theme"
:style="inputStyle"
:size="inputSize"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
@blur="handleInputBlur"
/>
<n-button
v-else
@ -30,7 +31,11 @@
:size="inputSize"
@click="handleAddClick"
>
+ {{ localizedAdd }}
<template v-slot:icon>
<n-icon>
<add-outline />
</n-icon>
</template>
</n-button>
</div>
</template>
@ -42,21 +47,34 @@ import asformitem from '../../_mixins/asformitem'
import locale from '../../_mixins/locale'
import NTag from './main'
import commonProps from './commonProps'
import NIcon from '../../Icon'
import addOutline from '../../_icons/add-outline'
export default {
name: 'NDynamicTags',
components: {
NTag
NTag,
NIcon,
addOutline
},
mixins: [withapp, themeable, locale('Tag'), asformitem({
change: 'change'
})],
mixins: [
withapp,
themeable,
locale('Tag'),
asformitem({
change: 'change'
})
],
model: {
name: 'value',
event: 'change'
},
props: {
...commonProps,
closable: {
type: Boolean,
default: true
},
value: {
type: Array,
default: () => {
@ -67,8 +85,7 @@ export default {
type: Object,
default: () => {
return {
marginRight: '5px',
marginBottom: '5px'
marginRight: '6px'
}
}
},
@ -76,7 +93,7 @@ export default {
type: Object,
default: () => {
return {
width: '50px'
width: '64px'
}
}
}
@ -84,7 +101,8 @@ export default {
data () {
return {
inputValue: '',
inputVisible: false
inputVisible: false,
inputForceFocused: true
}
},
computed: {
@ -111,12 +129,17 @@ export default {
this.$emit('change', tags)
}
this.inputVisible = false
this.inputForceFocused = true
this.inputValue = ''
},
handleInputBlur () {
this.handleInputConfirm()
},
handleAddClick () {
this.inputVisible = true
this.$nextTick(() => {
this.$refs.tagInput.focus()
this.inputForceFocused = false
})
}
}

View File

@ -17,7 +17,7 @@ export default {
},
closable: {
type: Boolean,
default: true
default: false
},
disabled: {
type: Boolean,

View File

@ -1,3 +1,5 @@
import { getPortalTarget } from '../../../_utils/component/portal'
function cleanUp (content, target) {
if (content && target && target.contains(content)) {
target.removeChild(content)
@ -6,14 +8,6 @@ function cleanUp (content, target) {
export default {
name: 'NBasePortal',
inject: {
NModal: {
default: null
},
NDrawer: {
default: null
}
},
props: {
onMounted: {
type: Function,
@ -22,15 +16,7 @@ export default {
transferTarget: {
type: Function,
default: function () {
const NModal = this.NModal
if (NModal) {
return NModal.getDetachTarget()
}
const NDrawer = this.NDrawer
if (NDrawer) {
return NDrawer.getDetachTarget()
}
return document.body
return getPortalTarget(this)
}
}
},
@ -47,7 +33,7 @@ export default {
* Since content may be detached in modal, waiting animation done is
* important. A more elegant solution is needed.
*/
if (this.NModal || this.NDrawer) {
if (getPortalTarget(this, true)) {
setTimeout(() => {
cleanUp(content, target)
}, 300)

View File

@ -1,4 +1,5 @@
import withapp from './withapp'
import { getPortalTarget } from '../_utils/component/portal'
function cleanUp (content, target) {
if (content && target && target.contains(content)) {
@ -16,27 +17,11 @@ function cleanUp (content, target) {
*/
export default {
mixins: [ withapp ],
inject: {
NModal: {
default: null
},
NDrawer: {
default: null
}
},
props: {
detachTarget: {
type: Function,
default: function () {
const NModal = this.NModal
if (NModal) {
return NModal.getDetachTarget()
}
const NDrawer = this.NDrawer
if (NDrawer) {
return NDrawer.getDetachTarget()
}
return document.body
return getPortalTarget(this)
}
},
detachable: {
@ -103,7 +88,7 @@ export default {
* Since content may be detached in modal, waiting animation done is
* important. A more elegant solution is needed.
*/
if (this.NModal || this.NDrawer) {
if (getPortalTarget(this, true)) {
setTimeout(() => {
cleanUp(content, target)
}, 300)

View File

@ -0,0 +1,19 @@
/**
* @param {VueComponentInstance} instance
* @param {boolean} returnBoolean if set to true, it returns whether the instance
* is inside a modal or a drawer
*/
export function getPortalTarget (instance, returnBoolean = false) {
let cursor = instance.$parent
while (cursor) {
const componentName = cursor.$options.name
if (
componentName === 'NModalContent' ||
componentName === 'NDrawerContent'
) {
return returnBoolean ? true : cursor.getDetachTarget()
}
cursor = cursor.$parent
}
return returnBoolean ? false : document.body
}

View File

@ -19,6 +19,20 @@
padding-top: 0px;
}
}
@include m(left-arrow-placement) {
@include e(header) {
@include b(collapse-item-arrow) {
margin-right: 4px;
}
}
}
@include m(right-arrow-placement) {
@include e(header) {
@include b(collapse-item-arrow) {
margin-left: 4px;
}
}
}
@include b(collapse-item) {
margin-left: 32px;
}
@ -29,8 +43,10 @@
@include m(active) {
@include e(header) {
@include m(active) {
@include b(icon) {
transform: rotate(90deg);
@include b(collapse-item-arrow) {
@include b(icon) {
transform: rotate(90deg);
}
}
}
}
@ -48,15 +64,19 @@
position: relative;
cursor: pointer;
padding: 16px 0 0 0;
@include b(icon) {
transition: transform .15s $--n-ease-in-out-cubic-bezier, $--n-icon-transition;
font-size: 16px;
margin-right: 4px;
@include b(collapse-item-arrow) {
display: flex;
@include b(icon) {
transition: transform .15s $--n-ease-in-out-cubic-bezier, $--n-icon-transition;
font-size: 16px;
}
}
}
color: $--collapse-header-text-color;
@include b(icon) {
fill: $--collapse-header-text-color;
@include b(collapse-item-arrow) {
@include b(icon) {
fill: $--collapse-header-text-color;
}
}
}
@include e(content-inner) {

View File

@ -11,6 +11,23 @@
stroke: $--message-icon-color;
}
}
@if $type == 'loading' {
@include e(close) {
@include b(icon) {
cursor: pointer;
fill: map-get($--message-loading-close-color, 'default');
stroke: map-get($--message-loading-close-color, 'default');
&:hover {
fill: map-get($--message-loading-close-color, 'hover');
stroke: map-get($--message-loading-close-color, 'hover');
}
&:active {
fill: map-get($--message-loading-close-color, 'active');
stroke: map-get($--message-loading-close-color, 'active');
}
}
}
}
}
}
@ -81,6 +98,31 @@
font-size: 20px;
}
}
@include e(close) {
height: 40px;
display: flex;
align-items: center;
font-size: 19px;
margin-left: 12px;
}
}
@include e(close) {
@include b(icon) {
cursor: pointer;
fill: map-get($--message-close-color, 'default');
stroke: map-get($--message-close-color, 'default');
&:hover {
fill: map-get($--message-close-color, 'hover');
stroke: map-get($--message-close-color, 'hover');
}
&:active {
fill: map-get($--message-close-color, 'active');
stroke: map-get($--message-close-color, 'active');
}
}
}
@include m(closable) {
padding-right: 24px;
}
@include message-type-mixin('info');
@include message-type-mixin('success');

View File

@ -144,4 +144,8 @@
}
}
}
}
@include b(dynamic-tags) {
display: inline-flex;
}

View File

@ -7,6 +7,16 @@
"loading": $--n-secondary-text-color
) !global;
$--message-icon-color: rgba(255, 255, 255, .5) !global;
$--message-close-color: (
"default": rgba(255, 255, 255, .5),
"hover": rgba(255, 255, 255, .6),
"active": rgba(255, 255, 255, .4)
) !global;
$--message-loading-close-color: (
"default": rgba(255, 255, 255, .5),
"hover": rgba(255, 255, 255, .6),
"active": rgba(255, 255, 255, .4)
) !global;
$--message-background-color: (
"info": $--n-info-hs-color,
"success": $--n-success-hs-color,

View File

@ -7,6 +7,16 @@
"loading": $--n-secondary-text-color
) !global;
$--message-icon-color: rgba(255, 255, 255, .45) !global;
$--message-close-color: (
"default": rgba(255, 255, 255, .5),
"hover": rgba(255, 255, 255, .6),
"active": rgba(255, 255, 255, .4)
) !global;
$--message-loading-close-color: (
'default': $--n-close-color,
'hover': $--n-close-hover-color,
'active': $--n-close-color
) !global;
$--message-background-color: (
"info": $--n-info-color,
"success": $--n-success-color,