This commit is contained in:
mangogan 2019-08-06 10:32:49 +08:00
commit 1fb3daa967
120 changed files with 4501 additions and 740 deletions

1
.gitignore vendored
View File

@ -4,4 +4,5 @@ docDist
doc/dist
test/unit/coverage
package-lock.json
.vscode
*.swp

View File

View File

@ -68,12 +68,22 @@ Vue.use(naiveUi)
|Tooltip|😍|❌||
|Popover|😍|❌||
|InputNumber|😍|❌||
|Radio|🚧|||
|Radio|😍|||
|Tab|🚧|||
|Breadcrumb|🚧|||
|Badge|🚧|||
|Steps|🚧|||
## Todo
|Tag|🚧|||
|Divider|🚧|||
|Statistic|🚧|||
|PopConfirm|🚧|||
|Anchor|🚧|||
|BackTop|🚧|||
|Progress|🚧|||
|Timeline|🚧|||
|Card|🚧|||
|Collapse|🚧|||
|Cascader|🚧|||
1. Z-index management on `Select` & `Tooltip` & `Modal`(Low Priority)
2. Full featured table component(Medium Priority)
3. Form component(Medium Priority)

View File

@ -1,5 +1,5 @@
<template>
<div>
<div style="overflow: hidden;">
<div
style="width: 100%; border-radius: 8px; border: 2px solid #5c657eff; height: 39px; background-color: black; margin-bottom: 12px; display: flex; align-items: center; justify-content: center; cursor: pointer;"
@click="collapse = !collapse"

View File

@ -128,11 +128,13 @@ export default {
label: 'xiaobai1',
value: 'xiaobai1'
}],
onFilter: 'custom'
onFilter: 'custom',
ellipsis:true,//
},
{
title: 'Age',
key: 'age',
align: 'center',//
sortable: true,
order: 1, //
sorter: (a, b) => {
@ -729,7 +731,7 @@ export default {
let d = new Array(20).fill(0)
d = d.map((item, idx) => {
return {
name: 'xiaobai' + idx,
name: 'xiaobai213213132123213111121' + idx,
age: Math.ceil((Math.random() * 20))
}
})
@ -758,7 +760,7 @@ export default {
{
title: 'Name',
key: 'name',
filterMultiple: false,
ellipsis: true,
filterItems: [{
label: 'xiaobai1',
value: 'xiaobai1'
@ -784,6 +786,14 @@ export default {
key: 'age',
sortable: true,
order: 1,
className: (params) => {
let row = params.row
if (row.age > 10) {
return 'older'
}
return ''
},
align: 'center',
sorter: (a, b) => {
return a.age - b.age
},
@ -889,11 +899,11 @@ export default {
value: 15
}],
onFilter: (value, record) => {
switch (value) {
switch (+value) {
case 14:
return record.age <= value
return record.age <= +value
case 15:
return record.age >= value
return record.age >= +value
}
},
render: (h, params) => {
@ -935,10 +945,10 @@ export default {
filterMultiple: true,
filterItems: [{
label: '14',
value: '14'
value: 14
}, {
label: '15',
value: '15'
value: 15
}],
onFilter: (value, record) => {
return value.includes(record.age + '')
@ -986,3 +996,8 @@ export default {
}
}
</script>
<style>
.older{
background:rgb(255, 204, 146);
}
</style>

View File

@ -1,85 +0,0 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Alert
</n-gradient-text>
</div>
<div class="n-doc-body">
<div class="n-doc-section">
<div class="n-doc-section__header">
Custom Icon
</div>
<div class="n-doc-section__view">
<n-alert>
<template v-slot:icon>
<img
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOS44IDE4Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2ZmOTJhNDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkFsZXJ0IC0gSWNvbiAyPC90aXRsZT48ZyBpZD0iUGFnZS0xIj48ZyBpZD0iR3JvdXAtNC1Db3B5LTQiPjxnIGlkPSJHcm91cC01Ij48ZyBpZD0iTm90aWZpY2F0aW9uIj48cGF0aCBpZD0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTS43NSw1LjE5QTEuMzQsMS4zNCwwLDAsMCwwLDYuMzF2NS42MUExLjMsMS4zLDAsMCwwLC43NiwxM2wxMiw0LjkxYS41MS41MSwwLDAsMCwuNzYtLjQ5Vi41NGEuNDkuNDksMCwwLDAtLjc1LS40OFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMCkiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xNS4zLDQuNWE0LjUsNC41LDAsMCwxLDAsOSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwKSIvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4="
style="height: 20px; width: 22px;"
>
</template>
Will you still need me, will you still feed me When I'm sixty four?
</n-alert>
</div>
<div class="n-doc-section__source">
<textarea><n-alert>
<template v-slot:icon>
<img
src="data:image/svg+xml;base64,PHN2Zy...nPjwvZz48L3N2Zz4="
style="height: 20px; width: 22px;"
>
</template>
Will you still need me, will you still feed me When I'm sixty four?
</n-alert></textarea>
</div>
</div>
<div class="n-doc-section">
<div class="n-doc-section__header">
Buildin Icon
</div>
<div class="n-doc-section__view">
<n-alert icon="md-alert">
Well the Ukraine girls really knock me out. They leave the West behind
</n-alert>
</div>
<div class="n-doc-section__source">
<textarea><n-alert icon="md-alert">
Well the Ukraine girls really knock me out They leave the West behind
</n-alert></textarea>
</div>
</div>
<div class="n-doc-section">
<div class="n-doc-section__header">
No Icon
</div>
<div class="n-doc-section__view">
<n-alert>
Lucy in the sky with diamonds
</n-alert>
</div>
<div class="n-doc-section__source">
<textarea><n-alert>
Lucy in the sky with diamonds
</n-alert></textarea>
</div>
</div>
</div>
</div>
</template>
<script>
import docCodeEditorMixin from './docCodeEditorMixin'
export default {
mixins: [docCodeEditorMixin],
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,49 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Costum Icon
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-alert>
<template v-slot:icon>
<img
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOS44IDE4Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2ZmOTJhNDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkFsZXJ0IC0gSWNvbiAyPC90aXRsZT48ZyBpZD0iUGFnZS0xIj48ZyBpZD0iR3JvdXAtNC1Db3B5LTQiPjxnIGlkPSJHcm91cC01Ij48ZyBpZD0iTm90aWZpY2F0aW9uIj48cGF0aCBpZD0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTS43NSw1LjE5QTEuMzQsMS4zNCwwLDAsMCwwLDYuMzF2NS42MUExLjMsMS4zLDAsMCwwLC43NiwxM2wxMiw0LjkxYS41MS41MSwwLDAsMCwuNzYtLjQ5Vi41NGEuNDkuNDksMCwwLDAtLjc1LS40OFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMCkiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xNS4zLDQuNWE0LjUsNC41LDAsMCwxLDAsOSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwKSIvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4="
style="height: 19px; width: 19px;"
>
</template>
You don't know how lucky you are boy
</n-alert>
<n-alert
title="Back in the U.S.S.R."
type="error"
>
<template v-slot:icon>
<img
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOS44IDE4Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2ZmOTJhNDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPkFsZXJ0IC0gSWNvbiAyPC90aXRsZT48ZyBpZD0iUGFnZS0xIj48ZyBpZD0iR3JvdXAtNC1Db3B5LTQiPjxnIGlkPSJHcm91cC01Ij48ZyBpZD0iTm90aWZpY2F0aW9uIj48cGF0aCBpZD0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTS43NSw1LjE5QTEuMzQsMS4zNCwwLDAsMCwwLDYuMzF2NS42MUExLjMsMS4zLDAsMCwwLC43NiwxM2wxMiw0LjkxYS41MS41MSwwLDAsMCwuNzYtLjQ5Vi41NGEuNDkuNDksMCwwLDAtLjc1LS40OFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMCkiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xNS4zLDQuNWE0LjUsNC41LDAsMCwxLDAsOSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwKSIvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4="
style="height: 19px; width: 19px;"
>
</template>
Back in the U.S.<br>
Back in the U.S.<br>
Back in the U.S.S.R.
</n-alert>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,41 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Alert / n-alert
</n-gradient-text>
</div>
<div class="n-doc-body">
<type />
<costum-icon />
<using-built-in-icon />
<no-icon />
</div>
</div>
</template>
<script>
import costumIcon from './costumIcon.demo.vue'
import usingBuiltInIcon from './usingBuiltInIcon.demo.vue'
import NoIcon from './noIcon.demo.vue'
import type from './type.demo.vue'
export default {
components: {
costumIcon,
usingBuiltInIcon,
NoIcon,
type
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,30 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
noIcon
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-alert no-icon>
Yeah I'm back in the U.S.S.R.<br>
You don't know how lucky you are boys
</n-alert>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,50 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Type
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-alert
title="Info Text"
type="info"
>
Gee it's good to be back home
</n-alert>
<n-alert
title="Success Text"
type="success"
>
Leave it till tomorrow to unpack my case
</n-alert>
<n-alert
title="Warning Text"
type="warning"
>
Honey disconnect the phone
</n-alert>
<n-alert
title="Error Text"
type="error"
>
I'm back in the U.S.S.R.
</n-alert>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,36 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Builtin Icon
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-alert
icon="md-airplane"
title="Back in the U.S.S.R."
>
Well the Ukraine girls really knock me out<br>
They leave the West behind<br>
And Moscow girls make me sing and shout<br>
That Georgia's always on my mind<br>
Aw come on!
</n-alert>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,28 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
Write some demo here
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,75 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Select / n-select
</n-gradient-text>
</div>
<div
class="n-doc-body"
>
<multiple-cascader />
</div>
</div>
</template>
<script>
import multipleCascader from './multipleCascader.demo.vue'
export default {
components: {
multipleCascader
},
data () {
return {
selectedValue: null,
selectedArray: [],
items: [
{
label: 'ArtifactoryLabel',
value: 'Artifactory'
},
{
label: 'Registry',
value: 'Registry'
},
{
label: 'Public',
value: 'Public'
},
{
label: 'Custom',
value: 'Custom'
}
],
items2: [
{
label: 'Drive My Car',
children: [
{
label: 'test1',
value: 'test1'
},
{
label: 'test2',
value: 'test2'
}
]
}
]
}
},
methods: {
handleChange (newValue) {
alert(String(newValue))
},
handleChange2 (newValue) {
alert(JSON.stringify(newValue))
}
}
}
</script>

View File

@ -0,0 +1,136 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Multiple Cascader
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-cascader
v-model="selectedArray"
placeholder="Please Select Type"
:items="items"
style="flex-grow: 1; margin-right: 12px;"
/>
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">v-model: {{ JSON.stringify(selectedArray) }}</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
selectedArray: null,
items: [
{
label: 'Drive My Car lalalalalalalala',
children: [
{
label: 'test1',
value: 'test1'
},
{
label: 'test2',
value: 'test2'
}
]
},
{
label: '2',
children: [
{
label: 'test3',
children: [
{
label: 'test3-1',
value: 'test3-1'
},
{
label: 'test3-2',
value: 'test3-2'
}
]
},
{
label: 'test4',
value: 'test4'
}
]
},
{
label: '3',
children: [
{
label: 'test3',
value: 'test3'
},
{
label: 'test4',
value: 'test4'
}
]
},
{
label: '4',
children: [
{
label: 'test3',
value: 'test3'
},
{
label: 'test4',
value: 'test4'
}
]
},
{
label: '5',
children: [
{
label: 'test3',
value: 'test3'
},
{
label: 'test4',
value: 'test4'
}
]
},
{
label: '6',
children: [
{
label: 'test3',
value: 'test3'
},
{
label: 'test4',
value: 'test4'
}
]
},
{
label: '7',
children: [
{
label: 'test3',
value: 'test3'
},
{
label: 'test4',
value: 'test4'
}
]
}
]
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,28 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
Write some demo here
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,53 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Async
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-button @click="handleConfirm">
Async Confirm
</n-button>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
handleConfirm () {
const confirmInstance = this.$NModal.confirm({
title: 'Confirm',
content: 'Are u sure to ...?',
okText: 'Yes', // ok errorsuccess使
cancelText: 'No', //
onOk: () => {
console.log('click on ok', confirmInstance)
this.$NMessage.info('will be ok in 3 seconds')
confirmInstance.setLoading(true)
setTimeout(() => {
this.$NMessage.success('sure')
confirmInstance.remove()
}, 3000)
},
onCancel: () => {
this.$NMessage.error('cancel')
}
})
}
}
}
</script>

View File

@ -0,0 +1,35 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Confirm / $NModal
</n-gradient-text>
</div>
<div class="n-doc-body">
<type />
<asyncDemo />
</div>
</div>
</template>
<script>
import type from './type.demo.vue'
import asyncDemo from './async.demo.vue'
export default {
components: {
type,
asyncDemo
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,74 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Type
</div>
<div
class="n-doc-section__view"
style="display: block;"
>
<!--EXAMPLE_START-->
<n-button @click="handleConfirm">
Confirm
</n-button>
<n-button @click="handleSuccess">
Success
</n-button>
<n-button @click="handleError">
Error
</n-button>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
handleConfirm () {
const confirmInstance = this.$NModal.confirm({
title: 'Confirm',
content: '<b>Are u sure to ...?',
onOk: () => {
console.log('click on ok', confirmInstance)
this.$NMessage.success('sure')
},
onCancel: () => {
this.$NMessage.error('cancel')
}
})
},
handleSuccess () {
const confirmInstance = this.$NModal.success({
title: 'Success',
content: 'Premium designed icons for use in web, iOS, Android, and desktop apps. Support for SVG and web font. Completely open source, MIT licensed and built by the Ionic Framework team.',
onOk: () => {
console.log('click on ok', confirmInstance)
this.$NMessage.success('show tooltip')
}
})
},
handleError () {
const confirmInstance = this.$NModal.error({
title: 'Error',
content: '<b>这是一个测试?</b>hhahhaahahhahahsdiusah ashdusadu asdsadsadsadsadsa',
onOk: () => {
console.log('click on ok', confirmInstance)
this.$NMessage.success('I know..')
}
})
}
}
}
</script>

View File

@ -0,0 +1,82 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Actions
</div>
<div
class="n-doc-section__view"
style="flex-wrap: wrap;"
>
<!--EXAMPLE_START-->
<n-date-picker
v-model="ts1"
type="datetime"
style="margin-right: 12px; margin-bottom: 12px;"
:actions="['now']"
@change="onDateTimeChange"
/>
<n-date-picker
v-model="ts2"
type="date"
:actions="['confirm']"
style="margin-bottom: 12px;"
@change="onDateChange"
/>
<n-date-picker
v-model="ts3"
type="datetimerange"
style="margin-bottom: 12px;"
:actions="['clear']"
@change="onDateTimeChange"
/>
<n-date-picker
v-model="ts4"
type="daterange"
:actions="null"
style="margin-bottom: 12px;"
@change="onDateChange"
/>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
ts1: null,
ts2: 0,
ts3: null,
ts4: null
}
},
methods: {
onDateTimeChange (timestamp, dateTimeString) {
this.$NMessage.success(`${timestamp}, ${dateTimeString}`)
},
onDateChange (timestamp, dateString) {
this.$NMessage.success(`${timestamp}, ${dateString}`)
},
handleInputTs1 (v) {
if (v === '') {
this.ts1 = null
return
}
v = Number(v)
this.ts1 = Number.isNaN(v) ? null : v
},
handleInputTs2 (v) {
if (v === '') {
this.ts2 = null
return
}
v = Number(v)
this.ts2 = Number.isNaN(v) ? null : v
}
}
}
</script>

View File

@ -62,10 +62,18 @@ export default {
this.$NMessage.success(`${timestamp}, ${dateString}`)
},
handleInputTs1 (v) {
if (v === '') {
this.ts1 = null
return
}
v = Number(v)
this.ts1 = Number.isNaN(v) ? null : v
},
handleInputTs2 (v) {
if (v === '') {
this.ts2 = null
return
}
v = Number(v)
this.ts2 = Number.isNaN(v) ? null : v
}

View File

@ -12,6 +12,7 @@
<basic-usage />
<disabled />
<range />
<actions />
</div>
</div>
</template>
@ -19,13 +20,15 @@
<script>
import basicUsage from './basicUsage.demo.vue'
import disabled from './disabled.demo.vue'
import range from './range.demo'
import range from './range.demo.vue'
import actions from './actions.demo.vue'
export default {
components: {
basicUsage,
disabled,
range
range,
actions
},
data () {
return {

View File

@ -22,6 +22,7 @@
v-model="range3"
type="daterange"
/>
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">range1 v-model: {{ JSON.stringify(range1) }}
range2 v-model: {{ JSON.stringify(range2) }}

View File

@ -188,10 +188,15 @@
>
<n-input />
</n-form-item>
<n-form-item label="Top2">
<n-form-item
required
:label-width="80"
label="Top2"
>
<n-input />
</n-form-item>
<n-form-item
required
label-position="left"
label="Left"
>
@ -199,12 +204,14 @@
</n-form-item>
<n-form-item
label-position="center"
required
label="Center"
>
<n-input />
</n-form-item>
<n-form-item
label-position="right"
required
label="Right"
>
<n-input />
@ -287,7 +294,7 @@
/>
</n-form-item>
</template>
<span>Test nesting Form Item</span>
<span>Test nesting formItem in resetForm</span>
</n-popover>
<n-form-item
prop="muti.deep.select"
@ -366,6 +373,17 @@
:items="items"
/>
</n-form-item>
<n-form-item
prop="mutiSelect.0"
label="Select"
>
<n-select
v-model="validateForm.mutiSelect[0]"
multiple
placeholder="Please Select Type"
:items="items"
/>
</n-form-item>
<n-form-item label="Switch" prop="switch">
<n-switch v-model="validateForm.switch" />
</n-form-item>
@ -394,6 +412,13 @@
<script>
export default {
data () {
let arrayValidate = (rule, value, callback) => {
if (value.length <= 0) {
callback(new Error('input required'))
} else {
callback()
}
}
return {
validateForm: {
input: "",
@ -410,6 +435,9 @@
input: [
{ required: true, message: "input cannot be empty", trigger: "blur" }
],
'mutiSelect.0': [
{ validator: arrayValidate, trigger: 'change' }
],
"muti.deep.select": [
{
required: true,
@ -712,9 +740,12 @@ export default {
callback()
}
}
let arrayValidate = (rule, value, callback) => {
console.log('arrya validate value', value)
debugger
var arrayValidate = (rule, value, callback) => {
if (value.length <= 0) {
callback(new Error('input required'))
} else {
callback()
}
}
return {
form: {
@ -747,7 +778,7 @@ export default {
}
],
validateForm: {
input: 'input',
input: '',
muti: {
deep: {
select: 'Public'
@ -764,9 +795,9 @@ export default {
input: [
{ required: true, message: 'input cannot be empty', trigger: 'blur' }
],
'mutiSelect.0': [{
validator: arrayValidate, trigger: 'change'
}],
'mutiSelect.0': [
{ validator: arrayValidate, trigger: 'change' }
],
'muti.deep.select': [
{
required: true,

View File

@ -1,107 +0,0 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Message / $NMessage
</n-gradient-text>
</div>
<div class="n-doc-body">
<div class="n-doc-section">
<div class="n-doc-section__header">
Basic Usage
</div>
<div class="n-doc-section__view">
<n-button @click="emitMessage1">
Like a Rolling Stone
</n-button>
<n-button @click="emitMessage2">
Blowing in the Wind
</n-button>
<n-button @click="emitMessage3">
No Reply
</n-button>
</div>
<div class="n-doc-section__source">
<textarea><n-button @click="emitMessage1">
Like a Rolling Stone
</n-button>
<n-button @click="emitMessage2">
Blowing in the Wind
</n-button>
<n-button @click="emitMessage3">
No Reply
</n-button>
<script>
export default {
methods: {
emitMessage1 () {
this.$NMessage.error('Once upon a time you dressed so fine', { duration: 1000 })
},
emitMessage2 () {
this.$NMessage.warning('How many roads must a man walk down')
},
emitMessage3 () {
this.$NMessage.success('\'Cause you walked hand in hand With another man in my place')
}
}
}
</script></textarea>
</div>
</div>
<div class="n-doc-section">
<div class="n-doc-section__header">
Custom Icon
</div>
<div class="n-doc-section__view">
<n-button @click="emitMessage4">
Help!
</n-button>
</div>
<div class="n-doc-section__source">
<textarea>
<n-button @click="emitMessage4">
Help!
</n-button>
<script>
export default {
methods: {
emitMessage4 () {
this.$NMessage.warning('I never needed anybody\'s help in any way', { icon: 'ios-alert' })
}
}
}
</script></textarea>
</div>
</div>
</div>
</div>
</template>
<script>
import docCodeEditorMixin from './docCodeEditorMixin'
export default {
mixins: [docCodeEditorMixin],
data () {
return {
}
},
methods: {
emitMessage1 () {
this.$NMessage.error('Once upon a time you dressed so fine', { duration: 1000 })
},
emitMessage2 () {
this.$NMessage.warning('How many roads must a man walk down')
},
emitMessage3 () {
this.$NMessage.success('\'Cause you walked hand in hand With another man in my place')
},
emitMessage4 () {
this.$NMessage.warning('I never needed anybody\'s help in any way', { icon: 'ios-hourglass' })
}
}
}
</script>

View File

@ -0,0 +1,52 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Basic Usage
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-button @click="emitInfo">
Info
</n-button>
<n-button @click="emitError">
Error
</n-button>
<n-button @click="emitWarning">
Warning
</n-button>
<n-button @click="emitSuccess">
Success
</n-button>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
emitInfo () {
this.$NMessage.info('I don\'t know why nobody told you how to unfold your love')
},
emitError () {
this.$NMessage.error('Once upon a time you dressed so fine')
},
emitWarning () {
this.$NMessage.warning('How many roads must a man walk down')
},
emitSuccess () {
this.$NMessage.success('\'Cause you walked hand in hand With another man in my place')
}
}
}
</script>

View File

@ -0,0 +1,40 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-button @click="emitMessage">
Custom Icon
</n-button>
<!-- <n-button @click="emitMessageByRenderFunction">
Custom Icon(by render function)
</n-button> -->
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
emitMessage () {
this.$NMessage.warning('I never needed anybody\'s help in any way', { icon: 'ios-hourglass' })
}
// emitMessageByRenderFunction () {
// this.$NMessage.warning('I never needed anybody\'s help in any way', { icon: 'ios-hourglass' })
// }
}
}
</script>

View File

@ -0,0 +1,34 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Basic Usage
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-button @click="emitInfo">
Last for 5 second
</n-button>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods: {
emitInfo () {
this.$NMessage.info('I don\'t know why nobody told you how to unfold your love', { duration: 5000 })
}
}
}
</script>

View File

@ -0,0 +1,38 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
Message / $NMessage
</n-gradient-text>
</div>
<div class="n-doc-body">
<basic-usage />
<custom-icon />
<duration />
</div>
</div>
</template>
<script>
import basicUsage from './basicUsage.demo.vue'
import customIcon from './customIcon.demo.vue'
import duration from './duration.demo.vue'
export default {
components: {
basicUsage,
customIcon,
duration
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -10,20 +10,33 @@
<!--EXAMPLE_START-->
<n-nimbus-icon
type="share"
size="24"
:size="24"
/>
<n-nimbus-icon
type="ban"
size="24"
:size="24"
/>
<n-nimbus-icon
type="pull-request"
size="24"
:size="24"
color="#63E2B7"
/>
<n-nimbus-icon
type="operate"
:size="24"
color="#63E2B7"
/>
<n-nimbus-icon
:size="24"
type="edit"
/>
<n-nimbus-icon
:size="24"
type="close"
/>
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Valid type: share, ban, pull-request</pre>
<pre class="n-doc-section__inspect">Valid type: share, ban, pull-request, operate, edit</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>

View File

@ -11,7 +11,7 @@
<n-button size="small">
<template v-slot:icon>
<n-nimbus-icon
type="pull-request"
type="share"
color="#63E2B7"
/>
</template>
@ -20,7 +20,7 @@
<n-button>
<template v-slot:icon>
<n-nimbus-icon
type="pull-request"
type="share"
color="#63E2B7"
/>
</template>
@ -29,7 +29,7 @@
<n-button size="tiny">
<template v-slot:icon>
<n-nimbus-icon
type="pull-request"
type="share"
color="#63E2B7"
/>
</template>
@ -38,7 +38,7 @@
<n-button icon-on-right>
<template v-slot:icon>
<n-nimbus-icon
type="pull-request"
type="share"
color="#63E2B7"
/>
</template>

View File

@ -57,12 +57,12 @@ export default {
name: 'PercentCircle',
props: {
request: {
type: Number
// default: 0
type: Number,
default: 0
},
usage: {
type: Number
// default: 0
type: Number,
default: 0
},
cx: {
type: Number,
@ -80,11 +80,9 @@ export default {
type: Number,
default: 22
},
text: {
type: String
},
id: {
type: String
key: {
type: String,
require: true
}
// width: {
// type: Number,

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-progress
type="circle"
:percentage="60"
/>
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
NSteps / n-steps
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,92 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Basic Usage
</div>
<div
class="n-doc-section__view"
style="flex-wrap: wrap;"
>
<!--EXAMPLE_START-->
<n-steps
:current="current"
:finish-status="finishStatus"
:current-status="currentStatus"
>
<n-step
title="I Me Mine"
description="All through the day, I me mine I me mine, I me mine"
/>
<n-step
title="Let It Be"
description="When I find myself in times of trouble Mother Mary comes to me"
/>
<n-step
title="Come Together"
description="Here come old flat top He come grooving up slowly"
/>
<n-step
title="Something"
description="Something in the way she moves Attracts me like no other lover"
/>
</n-steps>
<div
style="display: flex; justify-content: center; flex-wrap: wrap; margin-top: 48px;"
>
<n-button
icon="md-arrow-round-back"
@click="prev"
/><n-button
icon="md-arrow-round-forward"
@click="next"
/>
<n-button @click="currentStatus='error'">
current-status: error
</n-button>
<n-button @click="currentStatus='process'">
current-status: process
</n-button>
<n-button @click="finishStatus='error'">
finish-status: error
</n-button>
<n-button @click="finishStatus='process'">
finish-status: process
</n-button>
<n-button @click="finishStatus='success'">
finish-status: success
</n-button>
</div>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
current: null,
finishStatus: 'success',
currentStatus: 'error'
}
},
beforeDestroy () {
},
methods: {
next () {
if (this.current === null) this.current = 0
else if (this.current >= 3) this.current = null
else this.current++
},
prev () {
if (this.current === 0) this.current = null
else if (this.current === null) this.current = 3
else this.current--
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,28 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
Write some demo here
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,28 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scaffold
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
Write some demo here
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,34 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Fix Width
</div>
<div
class="n-doc-section__view"
style="flex-wrap: nowrap;"
>
<!--EXAMPLE_START-->
<n-tooltip :width="400">
<template v-slot:activator>
<n-button style="margin: 0;">
hello tooltip
</n-button>
</template>
I wish they all could be California girls. I wish they all could be California girls. I wish they all could be California girls.
</n-tooltip>
<!--EXAMPLE_END-->
</div>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>

View File

@ -13,6 +13,7 @@
<trigger />
<event />
<placement />
<fixWidth />
</div>
</div>
</template>
@ -22,9 +23,10 @@ import basicUsage from './basicUsage.demo.vue'
import trigger from './trigger.demo.vue'
import event from './event.demo.vue'
import placement from './placement.demo.vue'
import fixWidth from './fixWidth.demo'
export default {
components: { basicUsage, trigger, event, placement },
components: { basicUsage, trigger, event, placement, fixWidth },
data () {
return {

View File

@ -0,0 +1,116 @@
<template>
<n-modal v-model="isActive">
<template v-slot:activator>
<n-button
size="small"
@click="isActive = true"
>
Parklife
</n-button>
</template>
<n-nimbus-form-card
width="1032"
title="Parklife"
:deactivate="() => isActive = false"
>
<template v-slot:header>
v-slot:header
</template>
<template v-slot:footer>
v-slot:footer
</template>
<template v-slot:content>
<n-date-picker
v-model="time"
type="datetime"
/>
<n-select
v-model="selectedValue"
size="small"
placeholder="Please Select Type"
:items="items"
style="flex-grow: 1;"
/>
<n-tooltip
placement="bottom"
trigger="click"
style="margin-right: 12px;"
>
<template v-slot:activator>
<n-button style="margin: 0;">
California Girls(Click)
</n-button>
</template>
<span>
I wish they all could be California girls
</span>
</n-tooltip>
</template>
</n-nimbus-form-card>
</n-modal>
</template>
<script>
export default {
data () {
return {
isActive: true,
time: null,
selectedValue: null,
items: [
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0'
},
{
label: 'Drive My Car',
value: 'song1'
},
{
label: 'Norwegian Wood',
value: 'song2'
},
{
label: "You Won't See",
value: 'song3'
},
{
label: 'Nowhere Man',
value: 'song4'
},
{
label: 'Think For Yourseld',
value: 'song5'
},
{
label: 'The Word',
value: 'song6'
},
{
label: 'Michelle',
value: 'song7'
},
{
label: 'What goes on',
value: 'song8'
},
{
label: 'Girl',
value: 'song9'
},
{
label: "I'm looking through you",
value: 'song10'
},
{
label: 'In My Life',
value: 'song11'
},
{
label: 'Wait',
value: 'song12'
}
]
}
}
}
</script>

View File

@ -17,7 +17,3 @@ export default {
}
</script>
<style>
</style>

View File

@ -0,0 +1,32 @@
<template>
<div
ref="doc"
class="n-doc"
>
<div class="n-doc-header">
<n-gradient-text :font-size="20">
scaffold
</n-gradient-text>
</div>
<div class="n-doc-body">
<scaffold />
</div>
</div>
</template>
<script>
import scaffold from './scaffold.demo.vue'
export default {
components: {
scaffold
},
data () {
return {
}
},
methods: {
}
}
</script>

View File

@ -0,0 +1,141 @@
<template>
<div class="n-doc-section">
<div class="n-doc-section__header">
Scrollbar
</div>
<div
class="n-doc-section__view"
style="flex-wrap: wrap;"
>
<!--EXAMPLE_START-->
<div style="width: 400px; height: 300px;">
<n-scrollbar>
<div style="background: linear-gradient(red, blue); width: 800px; height: 500px;">
666
</div>
</n-scrollbar>
</div>
<div style="width: 400px; height: 300px;">
<n-scrollbar>
<div style="background: linear-gradient(red, blue); width: 400px; height: 500px;">
666
</div>
</n-scrollbar>
</div>
<div style="width: 400px; height: 300px;">
<n-scrollbar>
<div style="background: linear-gradient(red, blue); width: 800px; height: 300px;">
666
</div>
</n-scrollbar>
</div>
<div style="width: 400px; height: 300px;">
<n-scrollbar>
<div style="background: linear-gradient(red, blue); height: 300px;">
<div style="background: yellow; width: 100%; color: black;">
666
</div>
</div>
</n-scrollbar>
</div>
<div style="width: 400px;">
<n-scrollbar>
<n-advance-table
:columns="columns"
:data="data"
max-height="300px"
:on-change="onChange"
/>
</n-scrollbar>
</div>
<!--EXAMPLE_END-->
</div>
<pre class="n-doc-section__inspect">Inspect some value here</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
</div>
</template>
<script>
export default {
data () {
let d = new Array(20).fill(0)
d = d.map((item, idx) => {
return {
name: 'xiaobai' + idx,
age: 10 + Math.ceil(Math.random() * 10)
}
})
console.log(d)
return {
columns: [
{
title: 'Name',
key: 'name',
filterMultiple: false,
filterItems: [{
label: 'xiaobai1',
value: 'xiaobai1'
}],
onFilter: 'custom'
},
{
title: 'Age',
key: 'age',
sortable: true,
order: 1, //
sorter: (a, b) => {
// soter sorter
return a.age - b.age
},
filterMultiple: true, // onFilter
filterItems: [{
label: '14',
value: 14
}, {
label: '15',
value: 15
}],
onFilter: (value, record) => {
return value.includes(record.age)
// switch (value) {
// case 14:
// return record.age <= value
// case 15:
// return record.age >= value
// }
},
render: (h, params) => {
return <b>{params.row.age}</b>
}
},
{
title: '#',
render: (h, params) => {
return (
<n-button
style="margin:0;"
size="small"
onClick={() => this.handleClick(params)}
>
delete
</n-button>
)
}
}
],
data: d
}
},
methods: {
handleClick (params) {
alert('delete' + JSON.stringify(params))
},
onChange (...args) {
console.log(args)
}
}
}
</script>

View File

@ -3,7 +3,7 @@
<n-nimbus-service-layout
icon="md-contacts"
:name="`NAIVE UI (${version})`"
:padding-body="false"
:padding-body="true"
:items="items"
>
<router-view />
@ -59,6 +59,10 @@ export default {
name: 'Alert',
path: '/n-alert'
},
{
name: 'Badge',
path: '/n-badge'
},
{
name: 'Button',
path: '/n-button'
@ -67,6 +71,14 @@ export default {
name: 'Checkbox',
path: '/n-checkbox'
},
{
name: 'Collapse',
path: '/n-collapse'
},
{
name: 'Confirm',
path: '/n-confirm'
},
{
name: 'DatePicker',
path: '/n-date-picker'
@ -107,6 +119,10 @@ export default {
name: 'Popover',
path: '/n-popover'
},
{
name: 'Progress',
path: '/n-progress'
},
{
name: 'Radio',
path: '/n-radio'
@ -115,6 +131,14 @@ export default {
name: 'Select',
path: '/n-select'
},
{
name: 'Cascader',
path: '/n-cascader'
},
{
name: 'Steps',
path: '/n-steps'
},
{
name: 'Switch',
path: '/n-switch'
@ -123,10 +147,18 @@ export default {
name: 'Table',
path: '/n-table'
},
{
name: 'Tag',
path: '/n-tag'
},
{
name: 'TimePicker',
path: '/n-time-picker'
},
{
name: 'Timeline',
path: '/n-timeline'
},
{
name: 'Tooltip',
path: '/n-tooltip'
@ -151,6 +183,14 @@ export default {
{
name: 'RouterDebug',
path: '/n-router-debug'
},
{
name: 'ModalDebug',
path: '/n-modal-debug'
},
{
name: 'ScrollbarDebug',
path: '/n-scrollbar-debug'
}
]
}

View File

@ -16,6 +16,7 @@ import tableDemo from './components/tableDemo'
import advanceTableDemo from './components/advanceTableDemo'
import inputDemo from './components/inputDemo'
import selectDemo from './components/selectDemo'
import cascaderDemo from './components/cascaderDemo'
import modalDemo from './components/modalDemo'
import nimbusFormCardDemo from './components/nimbusFormCardDemo'
import messageDemo from './components/messageDemo'
@ -29,15 +30,24 @@ import radioDemo from './components/radioDemo'
import formDemo from './components/formDemo'
import tabDemo from './components/tabDemo'
import timePickerDemo from './components/timePickerDemo'
import confirmDemo from './components/confirmDemo'
import scrollbarDebug from './debugComponents/scrollbarDebug'
import badgeDemo from './components/badgeDemo'
import stepsDemo from './components/stepsDemo'
import notificationDemo from './components/notificationDemo'
import nimbusConfirmCardDemo from './components/nimbusConfirmCardDemo'
import paginationDemo from './components/paginationDemo'
import startPage from './components/startPage'
import collapseDemo from './components/collapseDemo'
import tagDemo from './components/tagDemo'
import timelineDemo from './components/timelineDemo'
import progressDemo from './components/progressDemo'
import demo from './demo'
import popoverDebug from './debugComponents/popoverDebug'
import routerDebug from './debugComponents/routerDebug'
import modalDebug from './debugComponents/modalDebug'
Vue.use(NaiveUI)
Vue.use(VueRouter)
@ -69,6 +79,7 @@ const routes = [
{ path: '/n-advance-table', component: advanceTableDemo },
{ path: '/n-input', component: inputDemo },
{ path: '/n-select', component: selectDemo },
{ path: '/n-cascader', component: cascaderDemo },
{ path: '/n-modal', component: modalDemo },
{ path: '/n-nimbus-form-card', component: nimbusFormCardDemo },
{ path: '/n-message', component: messageDemo },
@ -85,7 +96,17 @@ const routes = [
{ path: '/n-form', component: formDemo },
{ path: '/n-tab', component: tabDemo },
{ path: '/n-time-picker', component: timePickerDemo },
{ path: '/n-router-debug', component: routerDebug }
{ path: '/n-confirm', component: confirmDemo },
{ path: '/n-router-debug', component: routerDebug },
{ path: '/n-modal-debug', component: modalDebug },
{ path: '/n-scrollbar-debug', component: scrollbarDebug },
{ path: '/n-badge', component: badgeDemo },
{ path: '/n-steps', component: stepsDemo },
{ path: '/n-collapse', component: collapseDemo },
{ path: '/n-progress', component: progressDemo },
{ path: '/n-tag', component: tagDemo },
{ path: '/n-timeline', component: timelineDemo }
]
},
{

View File

@ -172,7 +172,7 @@ Vue.use(naiveUi)
</tr>
<tr>
<td>Radio</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;">😍</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
@ -200,9 +200,74 @@ Vue.use(naiveUi)
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Tag</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Divider</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Statistic</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>PopConfirm</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Anchor</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>BackTop</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Progress</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Timeline</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Card</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Collapse</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
<tr>
<td>Cascader</td>
<td style="text-align:center;">🚧</td>
<td style="text-align:center;"></td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="todo">Todo</h2>
<ol>
<li>Z-index management on <code>Select</code> &amp; <code>Tooltip</code> &amp; <code>Modal</code>(Low Priority)</li>
<li>Full featured table component(Medium Priority)</li>

View File

@ -12,11 +12,13 @@ import CheckBox from './packages/common/Checkbox'
import RoundButton from './packages/common/Button'
import Switch from './packages/common/Switch'
import Select from './packages/common/Select'
import Cascader from './packages/common/Cascader'
import Modal from './packages/common/Modal'
import Input from './packages/common/Input'
import Message from './packages/common/Message'
import Notification from './packages/common/Notification'
import Pagination from './packages/common/Pagination'
import Progress from './packages/common/Progress'
import Tooltip from './packages/common/Tooltip'
import Popup from './packages/common/Popover'
import Alert from './packages/common/Alert'
@ -33,6 +35,9 @@ import ServiceLayout from './packages/nimbus/ServiceLayout'
import NimbusFormCard from './packages/nimbus/FormCard'
import NimbusConfirmCard from './packages/nimbus/ConfirmCard'
import NimbusIcon from './packages/nimbus/Icon'
import Scrollbar from './packages/common/Scrollbar'
import Steps from './packages/common/Steps'
import Confirm from './packages/common/Confirm'
function install (Vue) {
Card.install(Vue)
@ -67,9 +72,14 @@ function install (Vue) {
InputNumber.install(Vue)
NimbusIcon.install(Vue)
Radio.install(Vue)
Cascader.install(Vue)
Form.install(Vue)
Tab.install(Vue)
TimePicker.install(Vue)
Scrollbar.install(Vue)
Steps.install(Vue)
Confirm.install(Vue)
Progress.install(Vue)
}
export default {

View File

@ -1,6 +1,6 @@
{
"name": "naive-ui",
"version": "0.2.37",
"version": "0.2.72",
"description": "",
"main": "index.js",
"scripts": {

View File

@ -1,17 +1,15 @@
<template>
<filterIcon
:status="filterStatus"
>
<filterIcon :status="filterStatus">
<ul class="n-table-filter-item">
<li
v-for="(item, idx) in items"
:key="item.value"
:class="computeItemClass(item)"
@click="handleSelect(item,idx)"
@click="handleSelect(item, idx)"
>
<span>{{ item.label }}</span>
<n-icon
v-show="checkedIndexs[item.value]"
v-show="checkedIndexs[item.value].isChecked === true"
type="md-checkmark"
size="14"
/>
@ -27,7 +25,6 @@ import Vue from 'vue'
export default {
components: {
filterIcon
},
props: {
filterItems: {
@ -49,17 +46,11 @@ export default {
},
data () {
const checkedIndexs = {}
this.filterItems.forEach((item) => {
checkedIndexs[item.value] = false
})
let items = this.filterItems.map((item) => {
return {
...item,
isChecked: false
}
this.filterItems.forEach((item, index) => {
checkedIndexs[item.value] = { isChecked: false, index }
})
return {
items,
// items,
emitData: null,
checkedIndexs
}
@ -67,31 +58,32 @@ export default {
computed: {
filterStatus () {
return !!this.emitData
}
// _emitData () {
// let res = []
// Object.keys(this.checkedIndexs).forEach((key) => {
// if (this.checkedIndexs[key] === true) {
// res.push(key)
// }
},
// checkedIndexs (val, oldVal) {
// const checkedIndexs = {}
// this.filterItems.forEach((item) => {
// checkedIndexs[item.value] = false
// })
// res = res.length ? res : null
// if (!this.filterMultiple) {
// res = res.length ? res[0] : null
// }
// this.$emit('on-filter', res)
// return res
// }
// return { checkedIndexs, ...oldVal }
// },
items () {
let items = this.filterItems.map((item) => {
return {
...item
// isChecked: false
}
})
return items
}
},
watch: {
checkedIndexs: {
handler () {
let res = []
Object.keys(this.checkedIndexs).forEach((key) => {
if (this.checkedIndexs[key] === true) {
res.push(key)
if (this.checkedIndexs[key].isChecked === true) {
let index = this.checkedIndexs[key].index
res.push(this.filterItems[index].value)
}
})
res = res.length ? res : null
@ -99,18 +91,24 @@ export default {
this.$emit('on-filter', { key: this.filterKey, value: res, filterFn: this.filterFn })
},
deep: true
},
filterItems () {
const checkedIndexs = {}
this.filterItems.forEach((item, index) => {
checkedIndexs[item.value] = { isChecked: false, index }
})
this.checkedIndexs = { ...checkedIndexs, ...this.checkedIndexs }
}
},
methods: {
setCheckedIndexs (arr) {
arr.forEach(value => {
this.checkedIndexs[value] !== undefined && Vue.set(this.checkedIndexs, value, true)
this.checkedIndexs[value].isChecked !== undefined && Vue.set(this.checkedIndexs[value], 'isChecked', true)
})
},
reset () {
Object.keys(this.checkedIndexs).forEach((key) => {
this.checkedIndexs[key] = false
this.checkedIndexs[key].isChecked = false
})
// this.items.forEach((item) => {
// item.isChecked = false
@ -118,12 +116,11 @@ export default {
},
handleSelect (item, idx) {
// single select
let isChecked = this.checkedIndexs[item.value]
let isChecked = this.checkedIndexs[item.value].isChecked
!this.filterMultiple && this.reset()
Vue.set(this.checkedIndexs, item.value, !isChecked)
// this.$nextTick(() => {
// this.$emit('on-filter', { key: this.filterKey, value: this.checkedIndexs })
// })
// this.checkedIndexs[item.value] = !isChecked
Vue.set(this.checkedIndexs[item.value], 'isChecked', !isChecked)
// this.checkedIndexs[item.value] = !isChecked
// if (!this.filterMultiple) {
@ -141,7 +138,7 @@ export default {
computeItemClass (item) {
return {
'n-table-filter-item': true,
'n-table-filter-item--selected': this.checkedIndexs[item.value]
'n-table-filter-item--selected': this.checkedIndexs[item.value].isChecked
}
}
}
@ -162,7 +159,7 @@ export default {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.n-table-filter-item li{
.n-table-filter-item li {
padding: 0 12px;
height: 27px;
align-items: center;
@ -178,17 +175,18 @@ export default {
line-height: 27px;
box-sizing: border-box;
padding: 0 12px;
transition: all .3s;
transition: all 0.3s;
cursor: pointer;
}
.n-table-filter-item li:hover{
background-color: rgba(96,220,178,0.3);
.n-table-filter-item li:hover {
background-color: rgba(96, 220, 178, 0.3);
}
.n-table-filter-item--selected{
background-color:rgba(96,220,178,0.3);
.n-table-filter-item--selected {
background-color: rgba(96, 220, 178, 0.3);
}
.n-table-filter-item--selected,.n-table-filter-item--selected i {
color: #63E2B7;
.n-table-filter-item--selected,
.n-table-filter-item--selected i {
color: #63e2b7;
}
</style>

View File

@ -1,13 +1,17 @@
<template>
<div ref="tableWrapper"
class="n-advance-tabel__wrapper">
<div
ref="tableWrapper"
class="n-advance-tabel__wrapper"
>
<div class="n-advance-table__operation">
<section class="n-advance-table__operation__bacth" />
<div class="n-advance-table__operation__custom">
<slot name="table-operation" />
</div>
<div v-if="search"
class="n-advance-table__operation__search">
<div
v-if="search"
class="n-advance-table__operation__search"
>
<searchInput
ref="search"
style=" margin-bottom: 18px;"
@ -27,13 +31,18 @@ class="n-advance-table__operation__search">
:key="i"
:style="computeCustomWidthStl(column)"
>
<col v-if="scrollBarWidth"
:width="scrollBarWidth" >
<col
v-if="scrollBarWidth"
:width="scrollBarWidth"
>
</colgroup>
<n-thead>
<n-tr>
<n-th v-for="(column, i) in columns"
:key="column.key">
<n-th
v-for="(column, i) in columns"
:key="column.key"
:style="computeAlign(column)"
>
{{ column.title }}
<SortIcon
v-if="column.sortable"
@ -53,7 +62,7 @@ class="n-advance-table__operation__search">
<!-- 优先自定义 -->
{{ column.filterDropdown && column.filterDropdown() }}
<!-- 否则默认渲染 -->
<sortDropDown
<filterDropDown
v-if="column.filterItems && !column.filterDropdown"
:ref="'filterDropDown_' + (column.key || i)"
:filter-fn="column.onFilter"
@ -89,10 +98,16 @@ class="n-advance-table__operation__search">
>
</colgroup>
<n-tbody>
<n-tr v-for="(rowData, i) in showingData"
:key="i">
<n-td v-for="column in columns"
:key="column.key">
<n-tr
v-for="(rowData, i) in showingData"
:key="i"
>
<n-td
v-for="column in columns"
:key="column.key"
:style="computeAlign(column)"
:class="computeTdClass(column,{row:rowData,index:i,key:column.key})"
>
<row
:index="i"
:row="rowData"
@ -101,8 +116,10 @@ class="n-advance-table__operation__search">
/>
</n-td>
</n-tr>
<div v-if="showingData.length === 0"
class="n-no-data-tip">
<div
v-if="showingData.length === 0"
class="n-no-data-tip"
>
No data
</div>
</n-tbody>
@ -112,8 +129,10 @@ class="n-no-data-tip">
v-if="pagination !== false && showingData.length"
class="n-advanced-table__pagination"
>
<n-pagination v-model="currentPage"
:page-count="pageCount" />
<n-pagination
v-model="currentPage"
:page-count="pageCount"
/>
</div>
</div>
</template>
@ -121,7 +140,7 @@ class="n-no-data-tip">
<script>
import row from '../row/index.js'
import SortIcon from '../sortIcon'
import sortDropDown from '../sortDropDown'
import filterDropDown from '../filterDropDown'
import searchInput from '../searchInput'
export default {
@ -129,7 +148,7 @@ export default {
components: {
row,
SortIcon,
sortDropDown,
filterDropDown,
searchInput
},
props: {
@ -313,6 +332,7 @@ export default {
}
},
watch: {
currentPage () {
if (this.pagination.custom === true) {
this.useRemoteChange()
@ -323,7 +343,8 @@ export default {
},
data () {
this.copyData = this.data.slice(0)
this.searchData = []
this.searchData = this.computeShowingData()
this.searchDataNoSort = null
},
currentSearchColumn () {
this.searchData = this.computeShowingData()
@ -360,6 +381,29 @@ export default {
// window.removeEventListener('resize', this.init)
},
methods: {
computeAlign (column) {
if (column.align) {
return {
'text-align': column.align
}
}
},
computeTdClass (column, params) {
let className = []
if (column.ellipsis) {
className.push('n-advanced-table__td-text-ellipsis')
}
if (!column.className) {
return className
}
if (typeof column.className === 'string') {
className.push(column.className)
} else if (typeof column.className === 'function') {
className.push(column.className(params))
}
console.log(className)
return className
},
/**
* {key:[value,value1],key1:[v1,v2]}
* {key:value}

View File

@ -1,7 +1,13 @@
<template>
<div class="n-alert">
<div
class="n-alert"
:class="{
[`n-alert--${type}`]: true,
'n-alert--no-icon': noIcon
}"
>
<div
v-if="$slots.icon || icon"
v-if="!noIcon"
class="n-alert__icon"
>
<slot
@ -10,12 +16,35 @@
/>
<n-icon
v-else-if="icon"
size="24"
:type="icon"
/>
<n-icon
v-else-if="type==='success'"
:type="'ios-checkmark-circle'"
/>
<n-icon
v-else-if="type==='info'"
:type="'ios-information-circle'"
/>
<n-icon
v-else-if="type==='warning'"
:type="'ios-alert'"
/>
<n-icon
v-else-if="type==='error'"
:type="'ios-close-circle'"
/>
</div>
<div class="n-alert__content">
<slot />
<div class="n-alert__body-wrapper">
<div
v-if="title !== null"
class="n-alert__title"
>
{{ title }}
</div>
<div class="n-alert__content">
<slot />
</div>
</div>
</div>
</template>
@ -31,6 +60,20 @@ export default {
icon: {
type: String,
default: null
},
title: {
type: String,
default: null
},
noIcon: {
type: Boolean,
default: false
},
type: {
validator (type) {
return ['info', 'warning', 'alert', 'success'].includes(type)
},
default: 'info'
}
}
}

View File

@ -0,0 +1,9 @@
/* istanbul ignore file */
import Cascader from './src/main.vue'
Cascader.install = function (Vue) {
console.log('register', Cascader.name)
Vue.component(Cascader.name, Cascader)
}
export default Cascader

View File

@ -0,0 +1,35 @@
<template>
<div
:key="data.value"
class="n-cascader-menu__item"
:class="itemClass"
>
{{ data.label }}
</div>
</template>
<script>
export default {
name: 'CasItem',
props: {
data: {
type: Object,
required: true
},
selected: {
type: Boolean,
required: true
}
},
computed: {
itemClass () {
let val = ''
if (this.data.children) {
val = 'n-cascader-menu__item-next'
} else if (this.selected) {
val = 'n-cascader-menu__item--selected'
}
return val
}
}
}
</script>

View File

@ -0,0 +1,113 @@
<template>
<span
ref="contentInner"
style="display:inline-block;white-space:nowrap;"
>
<div
v-if="data && data.length"
class="n-cascader-menu n-cascader-menu--multiple n-cascader-menu--default-size"
>
<CasItem
v-for="(item, index) in data"
:key="index"
:data="item"
:name="isSelected(item,parent)"
:selected="!!selected[isSelected(item)]"
:class="{
'n-cascader-menu__item--active':
activeLabel ===
item.label
}"
@click.native.stop="selectItem(item, $event)"
/>
</div>
<CasPanel
v-if="subList && subList.length"
:data="subList"
:parent="parentLabel"
:selected="selected"
@changeSelect="changeSelect"
/>
</span>
</template>
<script>
import CasItem from './CasItem.vue'
export default {
name: 'CasPanel',
components: {
CasItem
},
props: {
data: {
type: Array,
required: true
},
parent: {
type: String,
default: ''
},
selected: {
type: Object,
required: true
}
},
data () {
return {
subList: [],
activeLabel: '',
click: false,
parentLabel: this.parent
}
},
computed: {
isSelected () {
return function (item, parentl) {
let val = ''
if (this.click) {
if (this.parent) {
val = this.parent + '/' + item.label
}
} else {
if (this.parent) {
let index = this.parent.indexOf(item.label)
val = this.parent.substring(index) === item.label ? this.parent : this.parent + '/' + item.label
} else {
val = item.label
}
}
return val
}
}
},
watch: {
parent () {
this.parentLabel = this.parent
},
data () {
this.subList = []
}
},
methods: {
selectItem (item, event) {
if (item.children && item.children.length) {
this.activeLabel = item.label
this.subList = item.children
this.parentLabel = this.parent ? this.parent + '/' + item.label : item.label
} else {
this.activeLabel = ''
this.subList = []
let result = this.parent ? this.parent + '/' + item.label : item.label
this.parentLabel = this.parent ? this.parent : item.label
this.$set(this.selected, result, !this.selected[result])
this.changeSelect(result)
this.click = true
}
},
changeSelect (val) {
this.$emit('changeSelect', val)
}
}
}
</script>

View File

@ -0,0 +1,222 @@
<template>
<div
ref="select"
class="n-select"
:class="{
[`n-select--${size}-size`]: true,
'n-select--disabled': disabled
}"
@click="toggleMenu"
>
<div
ref="activator"
class="n-select-link"
:class="{
'n-select-link--active': active,
'n-select-link--selected': selectedItems&&selectedItems.length
}"
>
<div
class="n-select-link__tags"
:class="{
'n-select-link__tags--selected': selectedItems&&selectedItems.length
}"
>
<div
class="n-select-link__tag-wrapper"
>
<div
v-for="item in selectedItems"
:key="item"
class="n-select-link__tag"
>
<div class="n-select-link-tag__content">
{{ item }}
</div>
<n-icon
class="n-select-link-tag__icon"
type="md-close"
@click.stop="deleteItem(item)"
/>
</div>
</div>
</div>
<div
class="n-select-link__placeholder"
:class="{
'n-select-link__placeholder--verbose-transition': verboseTransition
}"
>
{{ placeholder }}
</div>
</div>
<div
ref="contentWrapper"
class="n-cascader-menu__content-wrapper"
>
<div
ref="content"
class="n-cascader-menu__content"
>
<div
ref="contentInner"
>
<transition name="n-select-menu--transition">
<CasPanel
v-if="active"
:data="items"
:selected-items="selectedItems"
:selected="selected"
@changeSelect="changeSelect"
/>
</transition>
</div>
</div>
</div>
</div>
</template>
<script>
import NIcon from '../../Icon/index'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import toggleable from '../../../mixins/toggleable'
import CasPanel from './CasPanel'
export default {
name: 'MutipleCascader',
components: {
NIcon,
CasPanel
},
mixins: [detachable, toggleable, placeable],
model: {
prop: 'selectedValue',
event: 'input'
},
props: {
items: {
type: Array,
required: true
},
// eslint-disable-next-line vue/require-prop-types
selectedValue: {
default: null
},
placeholder: {
type: String,
default: 'Please Select'
},
multiple: {
type: Boolean,
default: false
},
size: {
type: String,
default: 'default'
},
verboseTransition: {
type: Boolean,
default: false
},
emitItem: {
type: Boolean,
default: false
},
filterable: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
data () {
return {
lightBarTop: null,
showLightBar: false,
label: '',
labelPlaceholder: 'Please Select',
selectedItems: [],
selected: {}
}
},
watch: {
active (newValue) {
if (newValue === true) {
this.$nextTick().then(
() => {
document.addEventListener('click', this.nativeCloseMenu)
}
)
} else {
this.$nextTick().then(
() => {
document.removeEventListener('click', this.nativeCloseMenu)
}
)
}
},
selectedItems (val) {
let keys = Object.keys(this.selected)
for (let index of keys) {
this.$set(this.selected, index, false)
}
for (let index of val) {
this.setSelected(index)
}
this.$nextTick().then(this.updatePosition)
this.$emit('input', val)
}
},
beforeDestroy () {
document.removeEventListener('click', this.nativeCloseMenu)
},
methods: {
/**
* @param {string} value
*/
nativeCloseMenu (e) {
if (!this.$refs.select.contains(e.target)) {
this.deactivate()
}
},
toggleMenu () {
if (this.disabled) return
this.toggle()
},
changeSelect (val) {
let index = this.selectedItems.indexOf(val)
if (index < 0) {
this.selectedItems.push(val)
} else {
this.selectedItems.splice(index, 1)
}
if (this.selected[val]) {
this.setSelected(val)
}
},
setSelected (val) {
let arr = val.split('/')
let key = ''
for (let i = 0; i < arr.length; i++) {
if (i === 0) {
key = arr[i]
} else {
key = key + '/' + arr[i]
}
this.$set(this.selected, key, true)
}
},
deleteItem (val) {
let index = this.selectedItems.indexOf(val)
this.selectedItems.splice(index, 1)
this.$forceUpdate()
}
}
}
</script>

View File

@ -0,0 +1,79 @@
<script>
/**
* Warning: There are some potential problems if there are too many items!
*/
import MutipleCascader from './MutipleCascader'
export default {
name: 'NCascader',
model: {
prop: 'selectedValue',
event: 'input'
},
props: {
items: {
type: Array,
required: true
},
// eslint-disable-next-line vue/require-prop-types
selectedValue: {
default: null
},
placeholder: {
type: String,
default: 'Please Select'
},
multiple: {
type: Boolean,
default: false
},
size: {
type: String,
default: 'default'
},
verboseTransition: {
type: Boolean,
default: false
},
emitItem: {
type: Boolean,
default: false
},
filterable: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
data () {
return {
active: false
}
},
methods: {
handleInput (...args) {
this.$emit('input', ...args)
},
handleChange (...args) {
this.$emit('change', ...args)
},
handleSetActive (active) {
this.active = active
}
},
render (h) {
const on = {
input: this.handleInput.bind(this),
change: this.handleChange.bind(this),
setactive: this.handleSetActive.bind(this)
}
return h(MutipleCascader, {
props: { ...this.$props, active: this.active, placement: 'bottom-start', widthMode: 'activator' },
on
})
}
}
</script>

View File

@ -0,0 +1,8 @@
import Confirm from './src/index.js'
import ConfirmComp from './src/confirm.vue'
Confirm.install = function (Vue) {
Vue.prototype.$NModal = Confirm
Vue.component(ConfirmComp.name, ConfirmComp)
}
export default Confirm

View File

@ -0,0 +1,43 @@
import Vue from 'vue'
import Confirm from './confirm.vue'
Confirm.newInstance = properties => {
const _props = properties || {}
let Instance = new Vue({
data: _props,
render (h) {
return h(Confirm, {
props: _props
})
}
})
Instance.$mount()
// console.log('TCL: Instance', Instance)
const confirm = Instance.$children[0]
return {
remove () {
this.destroy()
},
setLoading (loading) {
confirm.loading = loading
console.log(confirm, confirm.loading)
},
update (options) {
Object.keys(options).forEach(key => {
confirm[key] = options[key]
})
},
component: confirm,
destroy () {
if (confirm) confirm.isActive = false
setTimeout(() => {
// confirm && confirm.$destroy()
Instance && Instance.$destroy()
}, 300)
}
}
}
export default Confirm

View File

@ -0,0 +1,127 @@
<template>
<n-modal
v-model="isActive"
@toggle="toggle"
>
<!-- <transition name="n-modal-content--transition"> -->
<div class="n-confirm">
<!-- <slot name="title"> -->
<div class="n-confirm__title">
<span class="n-confirm__title__text">
<n-icon
class="n-confirm__content__icon"
:type="iconType.type"
size="28"
:color="iconType.color"
/>
{{ title }}
</span>
<n-icon
type="md-close"
size="22"
style="cursor:pointer;"
@click="handleCancel"
/>
</div>
<!-- </slot> -->
<!-- <slot> -->
<div class="n-confirm__content">
<div
class="n-confirm__content__text"
v-html="content"
/>
</div>
<!-- </slot> -->
<!-- <slot name="footer"> -->
<div class="n-comfirm__footer">
<n-button
v-if="type === 'confirm'"
style="margin-bottom:0;"
round
size="small"
@click="handleCancel"
>
{{ canCancelText }}
</n-button>
<n-button
style="margin-bottom:0;"
round
:disabled="loading === true"
size="small"
type="primary"
auto-text-color
@click="handleOk"
>
{{ loading === true ? "Loading" : okText }}
</n-button>
</div>
<!-- </slot> -->
</div>
<!-- </transition> -->
</n-modal>
</template>
<script>
export default {
name: 'NConfirm',
data () {
return {
isActive: false,
content: 'content',
okText: 'OK',
canCancelText: 'Cancel',
type: 'error',
title: 'title',
loading: null,
onCancel: () => {},
onOk: () => {}
}
},
computed: {
iconType () {
const colors = {
'error': { type: 'ios-close-circle', color: '#FF92A4' },
'confirm': { type: 'ios-information-circle', color: '#FF92A4' },
'success': { type: 'ios-checkmark-circle', color: '#63E2B7' }
}
return colors[this.type]
}
},
mounted () {
// this.timer = setInterval(() => {
// console.log(1)
// }, 1000)
},
beforeDestroy () {
// clearInterval(this.timer)
},
methods: {
toggle (isActive) {
!isActive && setTimeout(() => {
this.$destroy()
}, 300)
},
handleCancel () {
this.onCancel()
this.isActive = false
setTimeout(() => {
this.$destroy()
}, 300)
},
handleOk () {
this.onOk()
if (this.loading !== true) { this.isActive = false }
}
// updateData (data) {
// Object.keys(data).forEach((key) => {
// this[key] = data[key]
// })
// },
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,44 @@
import confirm from './confirm.js'
let instanceStack = []
let confirmInstance
function getConfirmInstance () {
confirmInstance = confirm.newInstance()
instanceStack.push(confirmInstance)
return confirmInstance
}
function update (opts) {
const confirmInstance = getConfirmInstance()
confirmInstance.update(opts)
return confirmInstance
}
const Confirm = {
name: 'NConfirm',
confirm (options) {
return update({
type: 'confirm',
isActive: true,
...options
})
},
error (options) {
return update({
type: 'error',
isActive: true,
...options
})
},
success (options) {
return update({
type: 'success',
isActive: true,
...options
})
},
remove () {
let instance = instanceStack.pop()
instance.remove()
}
}
export default Confirm

View File

@ -60,7 +60,7 @@
:readonly="disabled ? 'disabled' : false"
@click="handleActivatorClick"
@focus="handleFocus"
@blur="handleDateTimeInputBlur"
@blur="handleTimeInputBlur"
@input="handleTimeInput"
>
<div class="n-date-picker__icon">
@ -72,34 +72,38 @@
</div>
<div
ref="contentWrapper"
class="n-content-wrapper"
class="n-content-wrapper n-content-wrapper--date-picker"
>
<div ref="content">
<datetime-panel
v-if="type === 'datetime'"
:value="value"
:active="active"
:actions="actions"
@input="handlePanelInput"
@close="closeCalendar"
/>
<date-panel
v-if="type === 'date'"
v-else-if="type === 'date'"
:value="value"
:active="active"
:actions="actions"
@input="handlePanelInput"
@close="closeCalendar"
/>
<daterange-panel
v-if="type === 'daterange'"
v-else-if="type === 'daterange'"
:value="value"
:active="active"
:actions="actions"
@input="handleRangePanelInput"
@close="closeCalendar"
/>
<datetimerange-panel
v-if="type === 'datetimerange'"
v-else-if="type === 'datetimerange'"
:value="value"
:active="active"
:actions="actions"
@input="handleRangePanelInput"
@close="closeCalendar"
/>
@ -113,6 +117,7 @@ import moment from 'moment'
import NIcon from '../../Icon'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import zindexable from '../../../mixins/zindexable'
import DatetimePanel from './panel/datetime'
import DatetimerangePanel from './panel/datetimerange'
import DatePanel from './panel/date'
@ -158,7 +163,8 @@ export default {
},
mixins: [
detachable,
placeable
placeable,
zindexable
],
props: {
disabled: {
@ -205,6 +211,10 @@ export default {
format: {
type: String,
default: null
},
actions: {
type: Array,
default: undefined
}
},
data () {
@ -266,11 +276,11 @@ export default {
*/
handlePanelInput (value, valueString) {
this.$emit('input', value, 'unavailable for now')
this.refreshDisplayTime(value)
this.refresh(value)
},
handleRangePanelInput (value, valueString) {
this.$emit('input', value, 'unavailable for now')
this.refreshDisplayRange(value)
this.refresh(value)
},
/**
* Refresh
@ -301,13 +311,13 @@ export default {
/**
* Blur
*/
handleDateTimeInputBlur () {
handleTimeInputBlur () {
if (this.disabled) return
const newSelectedDateTime = moment(this.displayTime, this.computedFormat, true)
const newSelectedDateTime = moment(this.displayTime, this.computedValidateFormat, true)
if (newSelectedDateTime.isValid()) {
this.$emit('input', newSelectedDateTime.valueOf())
} else {
this.refreshDisplayTime()
this.refreshDisplayTime(this.value)
}
this.isFocus = false
},

View File

@ -79,9 +79,17 @@
>
{{ dateItem.date }}
</div>
<div
v-if="!(actions && actions.length)"
style="height: 8px; width: 100%;"
/>
</div>
<div class="n-date-picker-calendar__actions">
<div
v-if="actions && actions.length"
class="n-date-picker-calendar__actions"
>
<n-button
v-if="actions.includes('now')"
size="tiny"
round
@click="setSelectedDateTimeToNow"
@ -89,6 +97,7 @@
Now
</n-button>
<n-button
v-if="actions.includes('confirm')"
size="tiny"
round
auto-text-color
@ -151,6 +160,10 @@ export default {
format: {
type: String,
default: DATETIME_FORMAT
},
actions: {
type: Array,
default: () => ['now', 'confirm']
}
},
data () {

View File

@ -167,17 +167,26 @@
>
{{ dateItem.date }}
</div>
<div
v-if="!(actions && actions.length)"
style="height: 8px; width: 100%;"
/>
</div>
</div>
<div class="n-date-picker-calendar__actions">
<div
v-if="actions && actions.length"
class="n-date-picker-calendar__actions"
>
<n-button
v-if="actions.includes('clear')"
size="tiny"
round
@click="clearValue"
>
Reset
Clear
</n-button>
<n-button
v-if="actions.includes('confirm')"
size="tiny"
round
auto-text-color
@ -249,6 +258,10 @@ export default {
format: {
type: String,
default: DATETIME_FORMAT
},
actions: {
type: Array,
default: () => ['clear', 'confirm']
}
},
data () {

View File

@ -95,9 +95,17 @@
>
{{ dateItem.date }}
</div>
<div
v-if="!(actions && actions.length)"
style="height: 8px; width: 100%;"
/>
</div>
<div class="n-date-picker-calendar__actions">
<div
v-if="actions && actions.length"
class="n-date-picker-calendar__actions"
>
<n-button
v-if="actions.includes('now')"
size="tiny"
round
@click="setSelectedDateTimeToNow"
@ -105,6 +113,7 @@
Now
</n-button>
<n-button
v-if="actions.includes('confirm')"
size="tiny"
round
auto-text-color
@ -172,6 +181,10 @@ export default {
format: {
type: String,
default: DATETIME_FORMAT
},
actions: {
type: Array,
default: () => ['now', 'confirm']
}
},
data () {

View File

@ -6,24 +6,40 @@
class="n-date-picker-calendar n-date-picker-calendar--datetimerange"
@click.capture="resetSelectingStatus"
>
<div class="n-date-picker-calendar__range-wrapper">
<div
class="n-date-picker-calendar__date-time-input-wrapper"
>
<n-input
v-model="startDateDisplayString"
class="n-date-picker-calendar__date-input"
placeholder="Select date"
@blur="handleStartDateInputBlur"
@input="handleStartDateInput"
/>
<n-time-picker
class="n-date-picker-calendar__time-input"
:value="startTimeValue"
stop-selector-bubble
@input="handleStartTimePickerInput"
/>
<div
class="n-date-picker-calendar__date-time-input-wrapper"
>
<n-input
v-model="startDateDisplayString"
class="n-date-picker-calendar__date-input"
placeholder="Select date"
@blur="handleStartDateInputBlur"
@input="handleStartDateInput"
/>
<n-time-picker
class="n-date-picker-calendar__time-input"
:value="startTimeValue"
stop-selector-bubble
@input="handleStartTimePickerInput"
/>
<div class="n-date-picker-calendar__arrow">
<n-icon type="ios-arrow-forward" />
</div>
<n-input
v-model="endDateDisplayString"
class="n-date-picker-calendar__date-input"
placeholder="Select date"
@blur="handleEndDateInputBlur"
@input="handleEndDateInput"
/>
<n-time-picker
class="n-date-picker-calendar__time-input"
:value="endTimeValue"
stop-selector-bubble
@input="handleEndTimePickerInput"
/>
</div>
<div class="n-date-picker-calendar__range-wrapper">
<div class="n-date-picker-calendar__month-modifier">
<div
class="n-date-picker-calendar__fast-prev"
@ -106,23 +122,6 @@
</div>
<div><div class="n-date-picker-calendar__vertical-divider" /></div>
<div class="n-date-picker-calendar__range-wrapper">
<div
class="n-date-picker-calendar__date-time-input-wrapper"
>
<n-input
v-model="endDateDisplayString"
class="n-date-picker-calendar__date-input"
placeholder="Select date"
@blur="handleEndDateInputBlur"
@input="handleEndDateInput"
/>
<n-time-picker
class="n-date-picker-calendar__time-input"
:value="endTimeValue"
stop-selector-bubble
@input="handleEndTimePickerInput"
/>
</div>
<div class="n-date-picker-calendar__month-modifier">
<div
class="n-date-picker-calendar__fast-prev"
@ -201,17 +200,26 @@
>
{{ dateItem.date }}
</div>
<div
v-if="!(actions && actions.length)"
style="height: 6px; width: 100%;"
/>
</div>
</div>
<div class="n-date-picker-calendar__actions">
<div
v-if="actions && actions.length"
class="n-date-picker-calendar__actions"
>
<n-button
v-if="actions.includes('clear')"
size="tiny"
round
@click="clearSelectedDateTime"
>
Reset
Clear
</n-button>
<n-button
v-if="actions.includes('confirm')"
size="tiny"
round
auto-text-color
@ -221,6 +229,10 @@
Confirm
</n-button>
</div>
<div
v-else
style="height: 12px"
/>
</div>
</transition>
</template>
@ -289,6 +301,10 @@ export default {
format: {
type: String,
default: DATETIME_FORMAT
},
actions: {
type: Array,
default: () => ['clear', 'confirm']
}
},
data () {
@ -335,12 +351,13 @@ export default {
}
},
valueAsMomentArray (newValue) {
if (this.isSelecting) return
if (newValue !== null) {
const [startMoment, endMoment] = newValue
this.startDateDisplayString = startMoment.format(DATE_FORMAT)
this.endDateDisplayString = endMoment.format(DATE_FORMAT)
this.syncCalendarTimeWithValue(newValue)
if (this.isSelecting) {
this.syncCalendarTimeWithValue(newValue)
}
} else {
this.startDateDisplayString = ''
this.endDateDisplayString = ''

View File

@ -68,30 +68,34 @@ export default {
* @param {Array} scope to specify the scope of validation
* @return {Boolean} validation passed or not
*/
validate (cb, scope = []) {
validate (cb, scope = [], target = this) {
let promise
let isCallback = typeof cb === 'function'
if (!isCallback && window.Promise) {
promise = new Promise((resolve, reject) => {
cb = valid => valid ? resolve(valid) : reject(valid)
cb = (valid) => valid ? resolve(valid) : reject(valid)
})
}
let valid = true
let fields = {}
this.$children.forEach((child, i) => {
for (let i = 0; i < target.$children.length; i++) {
let child = target.$children[i]
let componentName = child.$options.name
let flag = scope.length > 0 ? scope.indexOf(child.prop) > -1 : true
if (child.prop && flag) {
if (componentName === 'NFormItem' && child.prop && flag) {
child.validate('', (errors, field) => {
if (errors) {
valid = false
}
fields = Object.assign({}, fields, field)
})
} else if (['NFormItem', 'NForm'].indexOf(componentName) === -1) {
this.validate(null, [], child)
}
if (++i === this.$children.length && isCallback) {
if (i === target.$children.length - 1 && isCallback) {
cb(valid, fields)
}
})
}
if (promise) {
return promise
@ -103,7 +107,8 @@ export default {
resetForm (target = this) {
for (let i = 0; i < target.$children.length; i++) {
let child = target.$children[i]
if (child.$options.name === 'NFormItem' && child.prop) {
let componentName = child.$options.name
if (componentName === 'NFormItem' && child.prop) {
let keys = child.prop.split('.')
let obj = this.model
let j = 0
@ -117,9 +122,7 @@ export default {
if (child.validateFlag) {
child.clearValidateClass()
}
} else if (child.$options.name === 'NForm') {
break
} else {
} else if (['NFormItem', 'NForm'].indexOf(componentName) === -1) {
this.resetForm(child)
}
}

View File

@ -21,6 +21,11 @@
size="20"
type="md-close-circle"
/>
<n-icon
v-else-if="type === 'info'"
size="20"
type="md-information-circle"
/>
<n-icon
v-else-if="type === 'warning'"
size="20"

View File

@ -8,7 +8,7 @@ function attachMessageContainer () {
messageContainer = document.createElement('div')
messageContainer.classList.add('n-message', 'n-message__container')
messageContainer.style = `
z-index: 300;
z-index: 6000;
position: fixed;
left: 0;
right: 0;
@ -71,6 +71,11 @@ const NMessage = {
const messageCell = (new Vue({ ...NMessageCell, propsData: { option, content } })).$mount()
registerMessageEl(messageContainer, messageCell.$el, mixinOption(option))
},
info (content, option) {
option = mixinOption(option)
option.type = 'info'
this.notice(content, option)
},
success (content, option) {
option = mixinOption(option)
option.type = 'success'

View File

@ -8,7 +8,7 @@ function attachNotificationContainer () {
notificationContainer = document.createElement('div')
notificationContainer.classList.add('n-notification', 'n-notification__container')
notificationContainer.style = `
z-index: 300;
z-index: 4000;
position: fixed;
left: 0;
right: 15px;

View File

@ -37,6 +37,7 @@
:class="{
'n-popover__content--without-arrow': !arrow
}"
:style="style"
@mouseenter="handleMouseEnter"
>
<div
@ -63,6 +64,7 @@
:class="{
'n-popover__content--without-arrow': !arrow
}"
:style="style"
@mouseenter="handleMouseEnter"
>
<slot />
@ -77,12 +79,13 @@
import detachable from '../../../mixins/detachable'
import toggleable from '../../../mixins/toggleable'
import placeable from '../../../mixins/placeable'
import zindexable from '../../../mixins/zindexable'
import clickoutsideDelegate from '../../../utils/clickoutsideDelegate'
import moveoutsideDelegate from '../../../utils/moveoutsideDelegate'
export default {
// name: 'NPopover',
mixins: [detachable, toggleable, placeable],
mixins: [detachable, toggleable, placeable, zindexable],
props: {
duration: {
type: Number,
@ -105,6 +108,10 @@ export default {
raw: {
default: false,
type: Boolean
},
width: {
type: Number,
default: null
}
/**
* for debug usage
@ -120,6 +127,15 @@ export default {
delayTimerId: null
}
},
computed: {
style () {
const style = {}
if (this.width !== null) {
style.width = this.width + 'px'
}
return style
}
},
created () {
this.handleMoveOutsidePopover = this.handleMoveOutsidePopover.bind(this)
},

View File

@ -50,6 +50,10 @@ export default {
raw: {
type: Boolean,
default: false
},
width: {
type: Number,
default: null
}
},
data () {

View File

@ -0,0 +1,8 @@
/* istanbul ignore file */
import Progress from './src/main.vue'
Progress.install = function (Vue) {
Vue.component(Progress.name, Progress)
}
export default Progress

View File

@ -0,0 +1,50 @@
<template>
<div
:style="{
width: width + 'px',
height: width + 'px'
}"
>
<svg viewBox="0 0 100 100">
<g>
<path
d="
m 50 3
a 47 47 0 1 1 0 94
a 47 47 0 1 1 0 -94
"
stroke-width="3"
stroke-linecap="round"
stroke="white"
fill="none"
style="stroke-dasharray: 157, 1000; stroke-dashoffset: 0;"
/>
</g>
<g>
<path
d="
m 50 6
a 44 44 0 1 1 0 88
a 44 44 0 1 1 0 -88
"
stroke-width="3"
stroke-linecap="round"
stroke="red"
fill="none"
style="stroke-dasharray: 120, 1000; stroke-dashoffset: 0;"
/>
</g>
</svg>
</div>
</template>
<script>
export default {
name: 'NProgress',
data () {
return {
width: 126
}
}
}
</script>

View File

@ -0,0 +1,8 @@
/* istanbul ignore file */
import ScrollBar from './src/main.vue'
ScrollBar.install = function (Vue) {
Vue.component(ScrollBar.name, ScrollBar)
}
export default ScrollBar

View File

@ -0,0 +1,304 @@
<template>
<div
class="n-scrollbar"
@mouseenter="enterScrollWrapper"
@mouseleave="leaveScrollWrapper"
@dragstart.capture="handleDragStart"
>
<div
ref="scrollContainer"
class="n-scrollbar-container"
@scroll="handleScroll"
>
<div
ref="scrollContent"
class="n-scrollbar-content"
>
<slot />
</div>
</div>
<div
class="n-scrollbar-vertical-rail"
:style="{width: scrollbarSize}"
>
<transition name="n-scrollbar--transition">
<div
v-if="needVerticalScrollbar && showVeriticalScrollbar"
class="n-scrollbar-rail__scrollbar"
:style="{
height: verticalScrollbarHeightPx,
top: verticalScrollbarTopPx,
width: scrollbarSize,
borderRadius: scrollbarBorderRadius
}"
@mousedown="handleVerticalScrollMouseDown"
@mouseup="handleVerticalScrollMouseUp"
@mousemove="handleVerticalScrollMouseMove"
/>
</transition>
</div>
<div
class="n-scrollbar-horizontal-rail"
:style="{height: scrollbarSize}"
>
<transition name="n-scrollbar--transition">
<div
v-if="needHorizontalScrollbar && showHorizontalScrollbar"
class="n-scrollbar-rail__scrollbar"
:style="{
height: scrollbarSize,
width: horizontalScrollbarWidthPx,
left: horizontalScrollbarLeftPx
}"
@mousedown="handleHorizontalScrollMouseDown"
@mouseup="handleHorizontalScrollMouseUp"
@mousemove="handleHorizontalScrollMouseMove"
/>
</transition>
</div>
</div>
</template>
<script>
export default {
name: 'NScrollbar',
props: {
width: {
type: Number,
default: 5
},
duration: {
type: Number,
default: 0
}
},
data () {
return {
contentHeight: null,
contentWidth: null,
containerHeight: null,
containerWidth: null,
containerScrollTop: null,
containerScrollLeft: null,
horizontalScrollbarVanishTimerId: null,
verticalScrollbarVanishTimerId: null,
showHorizontalScrollbar: false,
showVeriticalScrollbar: false,
verticalScrollbarActivated: false,
horizontalScrollbarActivated: false,
memorizedVerticalTop: null,
memorizedHorizontalLeft: null,
memorizedMouseX: null,
memorizedMouseY: null
}
},
computed: {
verticalScrollbarHeight () {
if (this.containerHeight === null || this.contentHeight === null) return 0
else {
return (this.containerHeight * this.containerHeight / this.contentHeight)
}
},
verticalScrollbarHeightPx () {
return this.verticalScrollbarHeight + 'px'
},
horizontalScrollbarWidth () {
if (this.containerWidth === null || this.contentWidth === null) return 0
else {
return (this.containerWidth * this.containerWidth / this.contentWidth)
}
},
horizontalScrollbarWidthPx () {
return this.horizontalScrollbarWidth + 'px'
},
verticalScrollbarTop () {
if (this.containerHeight === null || this.containerScrollTop === null || this.contentHeight === null) return 0
else {
return (this.containerHeight * this.containerScrollTop / this.contentHeight)
}
},
verticalScrollbarTopPx () {
return this.verticalScrollbarTop + 'px'
},
horizontalScrollbarLeft () {
if (this.containerWidth === null || this.containerScrollLeft === null || this.contentWidth === null) return 0
else {
return (this.containerWidth * this.containerScrollLeft / this.contentWidth)
}
},
horizontalScrollbarLeftPx () {
return this.horizontalScrollbarLeft + 'px'
},
scrollbarSize () {
return this.width + 'px'
},
scrollbarBorderRadius () {
return this.width / 2 + 'px'
},
needVerticalScrollbar () {
return this.containerHeight !== null && this.contentHeight !== null && this.contentHeight > this.containerHeight
},
needHorizontalScrollbar () {
return this.containerWidth !== null && this.contentWidth !== null && this.contentWidth > this.containerWidth
}
},
watch: {
containerScrollTop () {
this.handleVerticalScroll()
},
containerScrollLeft () {
this.handleHorizontalScroll()
}
},
destroyed () {
window.clearTimeout(this.horizontalScrollbarVanishTimerId)
window.clearTimeout(this.verticalScrollbarVanishTimerId)
window.removeEventListener('mousemove', this.handleVerticalScrollMouseMove)
window.removeEventListener('mouseup', this.handleVerticalScrollMouseUp)
},
mounted () {
this.updateParameters()
},
methods: {
enterScrollWrapper () {
this.displayHorizontalScrollbar()
this.displayVerticalScrollbar()
this.updateParameters()
},
leaveScrollWrapper () {
this.hideScrollbar()
},
hideScrollbar () {
this.hideVerticalScrollbar()
this.hideHorizontalScrollbar()
},
hideVerticalScrollbar () {
if (this.verticalScrollbarVanishTimerId !== null) {
window.clearTimeout(this.verticalScrollbarVanishTimerId)
}
this.verticalScrollbarVanishTimerId = window.setTimeout(() => {
this.showVeriticalScrollbar = false
}, this.duration)
},
hideHorizontalScrollbar () {
if (this.horizontalScrollbarVanishTimerId !== null) {
window.clearTimeout(this.horizontalScrollbarVanishTimerId)
}
this.horizontalScrollbarVanishTimerId = window.setTimeout(() => {
this.showHorizontalScrollbar = false
}, this.duration)
},
displayHorizontalScrollbar () {
if (this.horizontalScrollbarVanishTimerId !== null) {
window.clearTimeout(this.horizontalScrollbarVanishTimerId)
}
this.showHorizontalScrollbar = true
},
displayVerticalScrollbar () {
if (this.verticalScrollbarVanishTimerId !== null) {
window.clearTimeout(this.verticalScrollbarVanishTimerId)
}
this.showVeriticalScrollbar = true
},
handleHorizontalScroll () {
// console.log('handleHorizontalScroll')
},
handleVerticalScroll () {
// console.log('handleVerticalScroll')
},
handleScroll () {
this.updateScrollParameters()
},
updateScrollParameters () {
if (this.$refs.scrollContainer) {
this.containerScrollTop = this.$refs.scrollContainer.scrollTop
this.containerScrollLeft = this.$refs.scrollContainer.scrollLeft
}
},
updatePositionParameters () {
/**
* Don't use getClientBoundingRect because element may be scale transformed
*/
if (this.$refs.scrollContent) {
this.contentHeight = this.$refs.scrollContent.offsetHeight
this.contentWidth = this.$refs.scrollContent.offsetWidth
}
if (this.$refs.scrollContainer) {
this.containerHeight = this.$refs.scrollContainer.offsetHeight
this.containerWidth = this.$refs.scrollContainer.offsetWidth
}
},
updateParameters () {
this.updatePositionParameters()
this.updateScrollParameters()
},
handleHorizontalScrollMouseDown (e) {
this.$emit('scrollstart')
this.horizontalScrollbarActivated = true
window.addEventListener('mousemove', this.handleHorizontalScrollMouseMove)
window.addEventListener('mouseup', this.handleHorizontalScrollMouseUp)
this.memorizedHorizontalLeft = this.containerScrollLeft
this.memorizedMouseX = e.clientX
},
handleHorizontalScrollMouseMove (e) {
if (this.horizontalScrollbarActivated) {
console.log('here')
window.clearTimeout(this.horizontalScrollbarVanishTimerId)
window.clearTimeout(this.verticalScrollbarVanishTimerId)
const dX = (e.clientX - this.memorizedMouseX)
let dScrollLeft = dX * (this.contentWidth - this.containerWidth) / (this.containerWidth - this.horizontalScrollbarWidth)
const toScrollLeftUpperBound = this.contentWidth - this.containerWidth
let toScrollLeft = this.memorizedHorizontalLeft + dScrollLeft
toScrollLeft = Math.min(toScrollLeftUpperBound, toScrollLeft)
toScrollLeft = Math.max(toScrollLeft, 0)
this.$refs.scrollContainer.scrollLeft = toScrollLeft
}
},
handleHorizontalScrollMouseUp (e) {
this.$emit('scrollend')
window.removeEventListener('mousemove', this.handleHorizontalScrollMouseMove)
window.removeEventListener('mouseup', this.handleHorizontalScrollMouseUp)
this.horizontalScrollbarActivated = false
this.updateParameters()
if (!this.$el.contains(e.target)) {
this.hideScrollbar()
}
},
handleVerticalScrollMouseDown (e) {
this.$emit('scrollstart')
this.verticalScrollbarActivated = true
window.addEventListener('mousemove', this.handleVerticalScrollMouseMove)
window.addEventListener('mouseup', this.handleVerticalScrollMouseUp)
this.memorizedVerticalTop = this.containerScrollTop
this.memorizedMouseY = e.clientY
},
handleVerticalScrollMouseMove (e) {
if (this.verticalScrollbarActivated) {
window.clearTimeout(this.horizontalScrollbarVanishTimerId)
window.clearTimeout(this.verticalScrollbarVanishTimerId)
const dY = (e.clientY - this.memorizedMouseY)
let dScrollTop = dY * (this.contentHeight - this.containerHeight) / (this.containerHeight - this.verticalScrollbarHeight)
const toScrollTopUpperBound = this.contentHeight - this.containerHeight
let toScrollTop = this.memorizedVerticalTop + dScrollTop
toScrollTop = Math.min(toScrollTopUpperBound, toScrollTop)
toScrollTop = Math.max(toScrollTop, 0)
this.$refs.scrollContainer.scrollTop = toScrollTop
}
},
handleVerticalScrollMouseUp (e) {
this.$emit('scrollend')
window.removeEventListener('mousemove', this.handleVerticalScrollMouseMove)
window.removeEventListener('mouseup', this.handleVerticalScrollMouseUp)
this.verticalScrollbarActivated = false
this.updateParameters()
if (!this.$el.contains(e.target)) {
this.hideScrollbar()
}
},
handleDragStart (e) {
e.preventDefault()
}
}
}
</script>

View File

@ -73,6 +73,7 @@
</div>
<div
ref="contentWrapper"
v-clickoutside="handleClickOutsideMenu"
class="n-select-menu__content-wrapper"
>
<div
@ -82,30 +83,41 @@
<transition name="n-select-menu--transition">
<div
v-if="active"
ref="contentInner"
class="n-select-menu n-select-menu--multiple"
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
class="n-select-menu-wrapper"
>
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in items"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
isSelected(item)
}"
@click.stop="toggleItemInMultipleSelect(item)"
@mouseenter="showLightBarTop"
ref="contentInner"
class="n-select-menu n-select-menu--multiple"
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
>
{{ item.label }}
<scrollbar
@scrollstart="handleMenuScrollStart"
@scrollend="handleMenuScrollEnd"
>
<div class="n-select-menu__item-wrapper">
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in items"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
isSelected(item)
}"
@click.stop="toggleItemInMultipleSelect(item)"
@mouseenter="showLightBarTop"
>
{{ item.label }}
</div>
</div>
</scrollbar>
</div>
</div>
</transition>
@ -119,17 +131,30 @@ import NIcon from '../../Icon/index'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import toggleable from '../../../mixins/toggleable'
import zindexable from '../../../mixins/zindexable'
import Scrollbar from '../../Scrollbar'
import clickoutside from '../../../directives/clickoutside'
import Emitter from '../../../mixins/emitter'
export default {
name: 'NMultipleSelect',
components: {
NIcon
NIcon,
Scrollbar
},
mixins: [detachable, toggleable, placeable],
directives: {
clickoutside
},
mixins: [detachable, toggleable, placeable, zindexable, Emitter],
model: {
prop: 'selectedValue',
event: 'input'
},
inject: {
formItem: {
default: null
}
},
props: {
items: {
type: Array,
@ -163,7 +188,6 @@ export default {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
@ -174,7 +198,7 @@ export default {
lightBarTop: null,
showLightBar: false,
label: '',
labelPlaceholder: 'Please Select'
scrolling: false
}
},
computed: {
@ -210,25 +234,13 @@ export default {
this.label = ''
}
},
active (newValue) {
if (newValue === true) {
this.$nextTick().then(
() => {
document.addEventListener('click', this.nativeCloseMenu)
}
)
} else {
this.$nextTick().then(
() => {
document.removeEventListener('click', this.nativeCloseMenu)
}
)
selectedItems (n) {
if (this.formItem) {
let vals = n.map(i => i.value)
this.dispatch('NFormItem', 'on-form-change', vals)
}
}
},
beforeDestroy () {
document.removeEventListener('click', this.nativeCloseMenu)
},
methods: {
/**
* @param {string} value
@ -258,8 +270,8 @@ export default {
if (!Array.isArray(this.selectedValue)) return false
return 1 + this.selectedValue.findIndex(value => value === item.value)
},
nativeCloseMenu (e) {
if (!this.$refs.select.contains(e.target)) {
handleClickOutsideMenu (e) {
if (!this.$refs.activator.contains(e.target) && !this.scrolling) {
this.deactivate()
}
},
@ -287,6 +299,14 @@ export default {
}
this.$emit('input', newSelectedValues)
this.$nextTick().then(this.updatePosition)
},
handleMenuScrollStart () {
this.scrolling = true
},
handleMenuScrollEnd () {
window.setTimeout(() => {
this.scrolling = false
}, 0)
}
}
}

View File

@ -38,44 +38,57 @@
<transition name="n-select-menu--transition">
<div
v-if="active"
ref="contentInner"
class="n-select-menu"
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
v-clickoutside="handleClickOutsideMenu"
class="n-select-menu-wrapper"
>
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in filteredItems"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
selectedValue ===
item.value
}"
@click.stop="toggleItemInSingleSelect(item)"
@mouseenter="showLightBarTop"
ref="contentInner"
class="n-select-menu"
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
>
{{ item.label }}
</div>
<div
v-if="label.length && !filteredItems.length"
class="n-select-menu__item n-select-menu__item--not-found"
>
{{
/**
* This method to activate hideLightBar is ridiculous, however using
* event handler still has some problem.
*/
hideLightBar()
}}
none result matched
<scrollbar
ref="scrollbar"
@scrollstart="handleMenuScrollStart"
@scrollend="handleMenuScrollEnd"
>
<div class="n-select-menu__item-wrapper">
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in filteredItems"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
selectedValue ===
item.value
}"
@click.stop="toggleItemInSingleSelect(item)"
@mouseenter="showLightBarTop"
>
{{ item.label }}
</div>
<div
v-if="label.length && !filteredItems.length"
class="n-select-menu__item n-select-menu__item--not-found"
>
{{
/**
* This method to activate hideLightBar is ridiculous, however using
* event handler still has some problem.
*/
hideLightBar()
}}
none result matched
</div>
</div>
</scrollbar>
</div>
</div>
</transition>
@ -89,10 +102,19 @@ import Emitter from '../../../mixins/emitter'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import toggleable from '../../../mixins/toggleable'
import zindexable from '../../../mixins/zindexable'
import Scrollbar from '../../Scrollbar'
import clickoutside from '../../../directives/clickoutside'
export default {
name: 'NSingleSelect',
mixins: [detachable, toggleable, placeable, Emitter],
components: {
Scrollbar
},
directives: {
clickoutside
},
mixins: [detachable, toggleable, placeable, zindexable, Emitter],
model: {
prop: 'selectedValue',
event: 'input'
@ -141,7 +163,8 @@ export default {
lightBarTop: null,
showLightBar: false,
label: '',
labelPlaceholder: 'Please Select'
labelPlaceholder: 'Please Select',
scrolling: false
}
},
computed: {
@ -165,6 +188,14 @@ export default {
}
},
watch: {
label () {
this.$nextTick().then(() => {
this.updatePosition()
if (this.$refs.scrollbar) {
this.$refs.scrollbar.updateParameters()
}
})
},
selectedItem (n, o) {
if (this.selectedItem !== null) {
this.label = this.selectedItem.label
@ -181,11 +212,6 @@ export default {
this.labelPlaceholder = this.selectedItem.label
this.label = ''
}
this.$nextTick().then(
() => {
document.addEventListener('click', this.handleClickOutsideMenu)
}
)
} else {
this.$refs.singleSelectInput.blur()
if (this.selectedItem) {
@ -194,11 +220,6 @@ export default {
this.label = ''
this.labelPlaceholder = this.placeholder
}
this.$nextTick().then(
() => {
document.removeEventListener('click', this.handleClickOutsideMenu)
}
)
}
}
},
@ -208,9 +229,6 @@ export default {
this.label = this.selectedItem.label
}
},
beforeDestroy () {
document.removeEventListener('click', this.handleClickOutsideMenu)
},
methods: {
/**
* @param {string} value
@ -240,7 +258,7 @@ export default {
return item.value === this.selectedValue
},
handleClickOutsideMenu (e) {
if (!this.$refs.select.contains(e.target)) {
if (!this.$refs.activator.contains(e.target) && !this.scrolling) {
this.deactivate()
}
},
@ -261,6 +279,14 @@ export default {
this.$emit('input', item.value)
this.emitChangeEvent(item, true)
this.closeMenu()
},
handleMenuScrollStart () {
this.scrolling = true
},
handleMenuScrollEnd () {
window.setTimeout(() => {
this.scrolling = false
}, 0)
}
}
}

View File

@ -0,0 +1,10 @@
/* istanbul ignore file */
import Steps from './src/main.vue'
import Step from './src/Step'
Steps.install = function (Vue) {
Vue.component(Steps.name, Steps)
Vue.component(Step.name, Step)
}
export default Steps

View File

@ -0,0 +1,113 @@
<template>
<div
class="n-step"
:class="{
'n-step--finished': finished,
'n-step--active': active,
[`n-step--${status}`]: status !== null
}"
>
<div class="n-step__splitor n-step__splitor--left" />
<div class="n-step-indicator">
<transition name="n-step-indicator--transition">
<div
v-if="finished && finishStatus !== 'process'"
class="n-step-indicator__icon"
>
<n-icon
v-if="status === 'success'"
type="md-checkmark"
/>
<n-icon
v-else-if="status === 'error'"
type="md-close"
/>
</div>
</transition>
<transition name="n-step-indicator--transition">
<div
v-if="!finished || (finished && finishStatus === 'process')"
class="n-step-indicator__index"
:class="{
'simulate-transparent-text': active
}"
>
{{ index }}
</div>
</transition>
</div>
<div class="n-step-content">
<div class="n-step-content__title">
<div class="n-step-content__title-inner">
{{ title }}
</div><div class="n-step__splitor n-step__splitor--right" />
</div>
<div
v-if="description !== null"
class="n-step-content__description"
>
{{ description }}
</div>
</div>
</div>
</template>
<script>
import NIcon from '../../Icon'
import texttransparentable from '../../../mixins/texttransparentable'
export default {
name: 'NStep',
components: {
NIcon
},
mixins: [texttransparentable],
props: {
finishStatus: {
type: String,
default: 'success',
validator (finishStatus) {
return ['process', 'success', 'error'].includes(finishStatus)
}
},
currentStatus: {
type: String,
default: 'process',
validator (currentStatus) {
return ['process', 'success', 'error'].includes(currentStatus)
}
},
finished: {
type: Boolean,
default: false
},
active: {
type: Boolean,
default: false
},
title: {
type: String,
default: null
},
description: {
type: String,
default: null
},
index: {
type: [Number, String],
default: null
}
},
computed: {
status () {
if (this.finished) {
return this.finishStatus
} else if (this.active) {
return this.currentStatus
} else {
return null
}
}
}
}
</script>

View File

@ -0,0 +1,49 @@
<script>
function wrapStep (step, i, { current, finishStatus, currentStatus }) {
if (step.componentOptions.tag === 'n-step') {
step.componentOptions.propsData = {
...step.componentOptions.propsData,
index: i + 1,
finished: !!current && current > i,
active: current === i,
finishStatus,
currentStatus
}
}
return step
}
function mapSteps (props, steps) {
return steps.map((step, i) => wrapStep(step, i, props))
}
export default {
name: 'NSteps',
props: {
current: {
type: Number,
default: null,
required: false
},
finishStatus: {
type: String,
default: 'success',
validator (finishStatus) {
return ['process', 'success', 'error'].includes(finishStatus)
}
},
currentStatus: {
type: String,
default: 'process',
validator (currentStatus) {
return ['process', 'success', 'error'].includes(currentStatus)
}
}
},
render (h) {
return h('div', {
staticClass: 'n-steps'
}, mapSteps({ ...this.$props }, this.$slots.default))
}
}
</script>

View File

@ -111,6 +111,7 @@ import moment from 'moment'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import clickoutside from '../../../directives/clickoutside'
import zindexable from '../../../mixins/zindexable'
const DEFAULT_FORMAT = 'HH:mm:ss'
const TIME_CONST = {
@ -152,7 +153,7 @@ export default {
directives: {
clickoutside
},
mixins: [detachable, placeable],
mixins: [detachable, placeable, zindexable],
props: {
stopSelectorBubble: {
type: Boolean,

View File

@ -5,13 +5,19 @@
:arrow="arrow"
:placement="placement"
:trigger="trigger"
:width="width"
@show="handleShow"
@hide="handleHide"
>
<template v-slot:activator>
<slot name="activator" />
</template>
<div class="n-tooltip__content">
<div
class="n-tooltip__content"
:class="{
'n-tooltip__content--fix-width': width !== null
}"
>
<slot />
</div>
</n-popover>
@ -68,6 +74,10 @@ export default {
arrow: {
default: false,
type: Boolean
},
width: {
type: Number,
default: null
}
},
methods: {

View File

@ -52,7 +52,7 @@ export default {
}
},
mounted () {
this.$refs.content.style = 'position: absolute;'
this.$refs.content.style.position = 'absolute'
this.$nextTick().then(() => {
this.registerScrollListeners()
this.registerResizeListener()
@ -79,7 +79,10 @@ export default {
// debugger
// console.log('scroll', activatorBoundingClientRect, contentBoundingClientRect)
const [placementTransform, suggsetedTransformOrigin] = calcPlacementTransfrom(this.placement, activatorBoundingClientRect, contentBoundingClientRect)
this.$refs.content.style = 'position: absolute;' + placementTransform + `transform-origin: ${suggsetedTransformOrigin};`
this.$refs.content.style.position = 'absolute'
this.$refs.content.style.top = placementTransform.top
this.$refs.content.style.left = placementTransform.left
this.$refs.content.style.transformOrigin = suggsetedTransformOrigin
this.$refs.content.setAttribute('n-suggested-transform-origin', suggsetedTransformOrigin)
if (this.widthMode === 'activator' && this.$refs.contentInner) {
this.$refs.contentInner.style.minWidth = activatorBoundingClientRect.width + 'px'

View File

@ -0,0 +1,30 @@
export default {
data () {
return {
ascendantBackgroundColor: null,
cssNode: null
}
},
mounted () {
let cursor = this.$el
while (cursor.parentElement) {
cursor = cursor.parentElement
const backgroundColor = getComputedStyle(cursor).backgroundColor
if (backgroundColor && backgroundColor !== 'rgba(0, 0, 0, 0)') {
this.ascendantBackgroundColor = backgroundColor
break
}
}
const id = 'x' + Math.random().toString(16).slice(9)
this.$el.setAttribute('n-id', id)
this.cssNode = document.createElement('style')
this.cssNode.innerHTML = `[n-id=${id}] .simulate-transparent-text {
color: ${this.ascendantBackgroundColor}!important;
}`
this.cssNode.type = 'text/css'
document.querySelector('head').appendChild(this.cssNode)
},
beforeDestroy () {
document.querySelector('head').removeChild(this.cssNode)
}
}

View File

@ -0,0 +1,27 @@
import zIndexManager from '../utils/dom/zIndexManager'
/**
* watch active on component,
* acquire new z-index on content when active is set to true
*
* dependency:
* $refs.contentWrapper
* $vm.active
*/
export default {
mounted () {
zIndexManager.registerElement(this.$refs.contentWrapper)
},
watch: {
active (newActive) {
console.debug('[zindexable.watch.active]:', newActive)
if (newActive) {
zIndexManager.setNewZIndex(this.$refs.contentWrapper)
}
}
},
beforeDestroy () {
zIndexManager.unregisterElement(this.$refs.contentWrapper)
}
}

View File

@ -5,28 +5,11 @@
>
<title>ban</title>
<g
id="Layer_2"
data-name="Layer 2"
:fill="color"
>
<g
id="Layer_1-2"
data-name="Layer 1"
>
<g id="Page-1">
<g id="Pods---Form---06-30-2019-Copy-10">
<g id="Group-17">
<g id="Disabled---SVG-Icon">
<path
id="Shape"
class="cls-1"
d="M50,0A50,50,0,1,0,85.36,14.64,50,50,0,0,0,50,0Zm0,89.58A39.59,39.59,0,0,1,18.19,26.44L73.56,81.81A39.41,39.41,0,0,1,50,89.58Zm31.81-16L26.44,18.19A39.59,39.59,0,0,1,81.81,73.56Z"
/>
</g>
</g>
</g>
</g>
</g>
<path
d="M50,0A50,50,0,1,0,85.36,14.64,50,50,0,0,0,50,0Zm0,89.58A39.59,39.59,0,0,1,18.19,26.44L73.56,81.81A39.41,39.41,0,0,1,50,89.58Zm31.81-16L26.44,18.19A39.59,39.59,0,0,1,81.81,73.56Z"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,24 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 99.9 99.9"
>
<title>close</title>
<g>
<path
d="M3,81.84l31.8-32L3,18.06A10.83,10.83,0,0,1,3,3a10.83,10.83,0,0,1,15,0l31.8,31.8L81.84,3a10.83,10.83,0,0,1,15,0,10.81,10.81,0,0,1,0,15l-32,31.8,32,32a10.63,10.63,0,0,1-15,15l-32-32-31.8,32a10.81,10.81,0,0,1-15,0A10.83,10.83,0,0,1,3,81.84Z"
/>
</g>
</svg>
</template>
<script>
export default {
props: {
color: {
type: String,
default: 'black'
}
}
}
</script>

View File

@ -0,0 +1,24 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 94.97 93.6"
>
<title>apply</title>
<g
:fill="color"
>
<path d="M75.8,83.3H10.3V20.5h36L56.5,10.3H7a7,7,0,0,0-7,7.1V86.5a7,7,0,0,0,7,7.1H79a7,7,0,0,0,7-7.1V37.2L75.8,47.3Z" /><path d="M94.3,12,83.1.7A2.61,2.61,0,0,0,81.4,0a2.84,2.84,0,0,0-1.7.7l-42,41.9a2.09,2.09,0,0,0-.7,1.3L34.5,57.6a2.29,2.29,0,0,0,.7,2.1,3.15,3.15,0,0,0,1.5.8,1.27,1.27,0,0,0,.6-.1l13.8-2.5a1.85,1.85,0,0,0,1.2-.7l42-41.9A2.35,2.35,0,0,0,94.3,12Z" />
</g>
</svg>
</template>
<script>
export default {
props: {
color: {
type: String,
default: 'black'
}
}
}
</script>

View File

@ -0,0 +1,23 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 99.14"
><title>operate</title>
<g
:fill="color"
>
<path d="M98.34,4.31,95.69,1.66a5.69,5.69,0,0,0-8,0l-35.38,37c-.1.1-.17.2-.27.31A16,16,0,0,0,29.46,55.38l11.08-8a4.27,4.27,0,0,1,5.94,1l4.14,5.78a4.26,4.26,0,0,1-1,5.93L38.55,68.08a16,16,0,0,0,22-19.68,8,8,0,0,0,.76-.68l37-35.38A5.69,5.69,0,0,0,98.34,4.31ZM93.6,11.47a3.58,3.58,0,1,1,0-5.06A3.6,3.6,0,0,1,93.6,11.47Z" /><path d="M41.4,99.14H54.74l1.13-9.4a39.13,39.13,0,0,0,14-5.81l7.46,5.85,9.44-9.43-5.86-7.46a39.21,39.21,0,0,0,5.81-14l9.41-1.13V44.4l-9.41-1.13a39,39,0,0,0-3.32-9.68L73.29,42.8A26.66,26.66,0,1,1,56.94,26.07l8.13-10.59a39.34,39.34,0,0,0-9.2-3.07L54.74,3H41.4l-1.14,9.4a39.21,39.21,0,0,0-14,5.81L18.8,12.37,9.36,21.8l5.85,7.46a39.31,39.31,0,0,0-5.81,14L0,44.4V57.75l9.4,1.13a39.39,39.39,0,0,0,5.81,14L9.36,80.35l9.44,9.43,7.45-5.85a39.21,39.21,0,0,0,14,5.81Z" />
</g>
</svg>
</template>
<script>
export default {
props: {
color: {
type: String,
default: 'black'
}
}
}
</script>

View File

@ -2,25 +2,19 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
><title>pull-request</title><g
id="Layer_2"
data-name="Layer 2"
><g
id="Layer_1-2"
data-name="Layer 1"
><g id="Page-1"><g
id="noun_Merge_1375873"
data-name="noun Merge 1375873"
><path
id="Shape"
class="cls-2"
:fill="color"
d="M4.38,13.45V6.55A3.37,3.37,0,0,0,7,3.33,3.42,3.42,0,0,0,3.5,0,3.42,3.42,0,0,0,0,3.33,3.37,3.37,0,0,0,2.62,6.55v6.9A3.37,3.37,0,0,0,0,16.67,3.42,3.42,0,0,0,3.5,20,3.42,3.42,0,0,0,7,16.67,3.37,3.37,0,0,0,4.38,13.45ZM1.75,3.33A1.7,1.7,0,0,1,3.5,1.67,1.7,1.7,0,0,1,5.25,3.33,1.71,1.71,0,0,1,3.5,5,1.71,1.71,0,0,1,1.75,3.33Zm1.75,15A1.67,1.67,0,1,1,3.5,15a1.67,1.67,0,1,1,0,3.33Z"
/><path
:fill="color"
class="cls-2"
d="M17.64,13.45V5.83A3.23,3.23,0,0,0,14.5,2.5H11.68l1.25-1.32L11.82,0,9.23,2.74a.86.86,0,0,0,0,1.18l2.59,2.75,1.11-1.18L11.68,4.17H14.5a1.61,1.61,0,0,1,1.57,1.66v7.62a3.31,3.31,0,0,0-2.36,3.22A3.24,3.24,0,0,0,16.86,20,3.24,3.24,0,0,0,20,16.67,3.3,3.3,0,0,0,17.64,13.45Zm-.78,4.88a1.67,1.67,0,1,1,1.57-1.66A1.61,1.61,0,0,1,16.86,18.33Z"
/></g></g></g></g></svg>
>
<title>pull-request</title>
<g
:fill="color"
>
<path
d="M4.38,13.45V6.55A3.37,3.37,0,0,0,7,3.33,3.42,3.42,0,0,0,3.5,0,3.42,3.42,0,0,0,0,3.33,3.37,3.37,0,0,0,2.62,6.55v6.9A3.37,3.37,0,0,0,0,16.67,3.42,3.42,0,0,0,3.5,20,3.42,3.42,0,0,0,7,16.67,3.37,3.37,0,0,0,4.38,13.45ZM1.75,3.33A1.7,1.7,0,0,1,3.5,1.67,1.7,1.7,0,0,1,5.25,3.33,1.71,1.71,0,0,1,3.5,5,1.71,1.71,0,0,1,1.75,3.33Zm1.75,15A1.67,1.67,0,1,1,3.5,15a1.67,1.67,0,1,1,0,3.33Z"
/>
<path
d="M17.64,13.45V5.83A3.23,3.23,0,0,0,14.5,2.5H11.68l1.25-1.32L11.82,0,9.23,2.74a.86.86,0,0,0,0,1.18l2.59,2.75,1.11-1.18L11.68,4.17H14.5a1.61,1.61,0,0,1,1.57,1.66v7.62a3.31,3.31,0,0,0-2.36,3.22A3.24,3.24,0,0,0,16.86,20,3.24,3.24,0,0,0,20,16.67,3.3,3.3,0,0,0,17.64,13.45Zm-.78,4.88a1.67,1.67,0,1,1,1.57-1.66A1.61,1.61,0,0,1,16.86,18.33Z"
/>
</g>
</svg>
</template>
<script>

View File

@ -5,33 +5,14 @@
>
<title>share</title>
<g
id="Layer_2"
data-name="Layer 2"
:fill="color"
>
<g
id="Layer_1-2"
data-name="Layer 1"
>
<g id="Symbols">
<g id="New-Page">
<g
id="noun_new-tab_1167424"
data-name="noun new-tab 1167424"
>
<path
id="Path"
class="cls-1"
d="M2.94,16h8.12A2.93,2.93,0,0,0,14,13.06v-5a.66.66,0,0,0-.68-.68h0a.66.66,0,0,0-.67.68v5a1.58,1.58,0,0,1-1.59,1.59H2.94a1.58,1.58,0,0,1-1.59-1.59V4.94A1.58,1.58,0,0,1,2.94,3.35h5a.66.66,0,0,0,.68-.67A.66.66,0,0,0,7.9,2h-5A2.93,2.93,0,0,0,0,4.94H0v8.12A2.93,2.93,0,0,0,2.94,16Z"
/>
<path
class="cls-1"
d="M16,5V.72a.34.34,0,0,0,0-.14s0,0,0,0,0,0,0-.06,0,0,0-.07a.08.08,0,0,0,0-.05.86.86,0,0,0-.19-.19l0,0a.18.18,0,0,0-.14-.09l-.07,0-.14,0H11a.68.68,0,0,0-.69.7.69.69,0,0,0,.69.7H13.6L7.21,7.81a.69.69,0,0,0,1,1L14.6,2.4V5a.69.69,0,0,0,.7.69h0A.73.73,0,0,0,16,5Z"
/>
</g>
</g>
</g>
</g>
<path
d="M2.94,16h8.12A2.93,2.93,0,0,0,14,13.06v-5a.66.66,0,0,0-.68-.68h0a.66.66,0,0,0-.67.68v5a1.58,1.58,0,0,1-1.59,1.59H2.94a1.58,1.58,0,0,1-1.59-1.59V4.94A1.58,1.58,0,0,1,2.94,3.35h5a.66.66,0,0,0,.68-.67A.66.66,0,0,0,7.9,2h-5A2.93,2.93,0,0,0,0,4.94H0v8.12A2.93,2.93,0,0,0,2.94,16Z"
/>
<path
d="M16,5V.72a.34.34,0,0,0,0-.14s0,0,0,0,0,0,0-.06,0,0,0-.07a.08.08,0,0,0,0-.05.86.86,0,0,0-.19-.19l0,0a.18.18,0,0,0-.14-.09l-.07,0-.14,0H11a.68.68,0,0,0-.69.7.69.69,0,0,0,.69.7H13.6L7.21,7.81a.69.69,0,0,0,1,1L14.6,2.4V5a.69.69,0,0,0,.7.69h0A.73.73,0,0,0,16,5Z"
/>
</g>
</svg>
</template>

View File

@ -16,25 +16,46 @@
v-else-if="type==='pull-request'"
:color="color"
/>
<span v-else>icon-type is invalid</span>
<operate-icon
v-else-if="type==='operate'"
:color="color"
/>
<edit-icon
v-else-if="type==='edit'"
:color="color"
/>
<close-icon
v-else-if="type==='close'"
:color="color"
/>
</i>
</template>
<script>
import shareIcon from './icons/share'
import banIcon from './icons/ban'
import pullRequestIcon from './icons/pullRequest'
import operateIcon from './icons/operate'
import editIcon from './icons/edit'
import closeIcon from './icons/close'
const validTypes = ['share', 'ban', 'pull-request', 'operate', 'edit']
export default {
name: 'NNimbusIcon',
components: {
shareIcon,
banIcon,
pullRequestIcon
pullRequestIcon,
operateIcon,
editIcon,
closeIcon
},
props: {
type: {
type: String,
default: ''
validator (type) {
return validTypes.includes(type)
},
required: true
},
size: {
type: [Number, String],
@ -49,10 +70,15 @@ export default {
styles () {
let style = {}
if (this.size) {
if (this.size.endsWith('%') || this.size.endsWith('px')) {
if (typeof this.size === 'number') {
style['width'] = this.size + 'px'
style['height'] = this.size + 'px'
} else if (this.size.endsWith('%') || this.size.endsWith('px')) {
style['width'] = this.size
style['height'] = this.size
} else {
style['width'] = this.size + 'px'
style['height'] = this.size + 'px'
}
}
if (this.color) {

View File

@ -3,77 +3,87 @@
<div><slot name="header" /></div>
<div
class="n-nimbus-service-layout__body"
:class="{ 'n-nimbus-service-layout__body--collapsed': isCollapsed, 'n-nimbus-service-layout__body--active': !isCollapsed, 'n-nimbus-service-layout__body--padded': paddingBody }"
:class="{ 'n-nimbus-service-layout__body--collapsed': isCollapsed, 'n-nimbus-service-layout__body--active': !isCollapsed }"
>
<slot />
<scrollbar>
<div
:style="{
padding: paddingBody ? '21px 48px' : 0
}"
>
<slot />
</div>
</scrollbar>
</div>
<div
class="n-nimbus-service-layout__drawer"
:class="{ 'n-nimbus-service-layout__drawer--collapsed': isCollapsed, 'n-nimbus-service-layout__drawer--active': !isCollapsed }"
>
<div class="n-nimbus-service-layout-drawer__item-wrapper">
<div class="n-nimbus-service-layout-drawer__header">
<div class="n-nimbus-service-layout-drawer-header__content">
<div class="n-nimbus-service-layout-drawer-header__icon">
<n-icon
:type="icon"
:size="22"
/>
<scrollbar>
<div class="n-nimbus-service-layout-drawer__header">
<div class="n-nimbus-service-layout-drawer-header__content">
<div class="n-nimbus-service-layout-drawer-header__icon">
<n-icon
:type="icon"
:size="22"
/>
</div>
{{ name }}
</div>
{{ name }}
</div>
</div>
<div class="n-nimbus-service-layout-drawer__divider" />
<div
v-for="item in itemsWithCollapseStatus"
:key="item.name"
>
<div class="n-nimbus-service-layout-drawer__divider" />
<div
v-if="!item.childItems"
class="n-nimbus-service-layout-drawer__item"
:class="{ 'n-nimbus-service-layout-drawer__item--active': activeItemName === item.name }"
@click="makeActive(item)"
>
<div class="n-nimbus-service-layout-drawer-item__icon" />
<span>{{ item.name }}</span>
</div>
<div
v-else
v-for="item in itemsWithCollapseStatus"
:key="item.name"
>
<div
class="n-nimbus-service-layout-drawer__item n-nimbus-service-layout-drawer__item--is-group-header"
:class="{
'n-nimbus-service-layout-drawer__item--group-item-is-choosed': !!(1 + item.childItems.findIndex(item => item.name === activeItemName)),
'n-nimbus-service-layout-drawer__item--collapsed': item.isCollapsed
}"
@click="toggleGroupHeaderCollapse(item.name)"
v-if="!item.childItems"
class="n-nimbus-service-layout-drawer__item"
:class="{ 'n-nimbus-service-layout-drawer__item--active': activeItemName === item.name }"
@click="makeActive(item)"
>
<div class="n-nimbus-service-layout-drawer-item__icon" />
<span>{{ item.name }}</span>
</div>
<div
:ref="item.name"
class="n-nimbus-service-layout-drawer__group-items"
:class="{
'n-nimbus-service-layout-drawer__group-items--collapsed': item.isCollapsed
}"
v-else
>
<div
class="n-nimbus-service-layout-drawer-group-items__inner-wrapper"
class="n-nimbus-service-layout-drawer__item n-nimbus-service-layout-drawer__item--is-group-header"
:class="{
'n-nimbus-service-layout-drawer__item--group-item-is-choosed': !!(1 + item.childItems.findIndex(item => item.name === activeItemName)),
'n-nimbus-service-layout-drawer__item--collapsed': item.isCollapsed
}"
@click="toggleGroupHeaderCollapse(item.name)"
>
<div class="n-nimbus-service-layout-drawer-item__icon" />
<span>{{ item.name }}</span>
</div>
<div
:ref="item.name"
class="n-nimbus-service-layout-drawer__group-items"
:class="{
'n-nimbus-service-layout-drawer__group-items--collapsed': item.isCollapsed
}"
>
<div
v-for="childItem in item.childItems"
:key="childItem.name"
class="n-nimbus-service-layout-drawer__item n-nimbus-service-layout-drawer__item--is-group-item"
:class="{ 'n-nimbus-service-layout-drawer__item--active': activeItemName === childItem.name }"
@click="makeActive(childItem)"
class="n-nimbus-service-layout-drawer-group-items__inner-wrapper"
>
<span>{{ childItem.name }}</span>
<div
v-for="childItem in item.childItems"
:key="childItem.name"
class="n-nimbus-service-layout-drawer__item n-nimbus-service-layout-drawer__item--is-group-item"
:class="{ 'n-nimbus-service-layout-drawer__item--active': activeItemName === childItem.name }"
@click="makeActive(childItem)"
>
<span>{{ childItem.name }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</scrollbar>
</div>
<div
class="n-nimbus-service-layout-drawer__toggle-button"
@ -86,8 +96,13 @@
</template>
<script>
import Scrollbar from '../../../common/Scrollbar'
export default {
name: 'NNimbusServiceLayout',
components: {
Scrollbar
},
props: {
icon: {
type: String,

View File

@ -1,37 +1,37 @@
export default function calcPlacementTransform (placement, activatorRect, popoverRect) {
export default function calcPlacementTransform (placement, activatorRect, contentRect) {
let contentLeft, contentTop
let suggesetedTransfromOrigin = 'none'
if (placement === 'top-start') {
contentTop = activatorRect.top - popoverRect.height
contentTop = activatorRect.top - contentRect.height
contentLeft = activatorRect.left
} else if (placement === 'top') {
contentTop = activatorRect.top - popoverRect.height
contentLeft = activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2
contentTop = activatorRect.top - contentRect.height
contentLeft = activatorRect.left + activatorRect.width / 2 - contentRect.width / 2
} else if (placement === 'top-end') {
contentTop = activatorRect.top - popoverRect.height
contentLeft = activatorRect.left + activatorRect.width - popoverRect.width
contentTop = activatorRect.top - contentRect.height
contentLeft = activatorRect.left + activatorRect.width - contentRect.width
} else if (placement === 'left-start') {
contentTop = activatorRect.top
contentLeft = activatorRect.left - popoverRect.width
contentLeft = activatorRect.left - contentRect.width
} else if (placement === 'left') {
contentTop = activatorRect.top + activatorRect.height / 2 - popoverRect.height / 2
contentLeft = activatorRect.left - popoverRect.width
contentTop = activatorRect.top + activatorRect.height / 2 - contentRect.height / 2
contentLeft = activatorRect.left - contentRect.width
} else if (placement === 'left-end') {
contentTop = activatorRect.top + activatorRect.height - popoverRect.height
contentLeft = activatorRect.left - popoverRect.width
contentTop = activatorRect.top + activatorRect.height - contentRect.height
contentLeft = activatorRect.left - contentRect.width
} else if (placement === 'right-start') {
contentTop = activatorRect.top
contentLeft = activatorRect.left + activatorRect.width
} else if (placement === 'right') {
contentTop = activatorRect.top + activatorRect.height / 2 - popoverRect.height / 2
contentTop = activatorRect.top + activatorRect.height / 2 - contentRect.height / 2
contentLeft = activatorRect.left + activatorRect.width
} else if (placement === 'right-end') {
contentTop = activatorRect.top + activatorRect.height - popoverRect.height
contentTop = activatorRect.top + activatorRect.height - contentRect.height
contentLeft = activatorRect.left + activatorRect.width
} else if (placement === 'bottom-start') {
const toWindowBottom = window.innerHeight - activatorRect.bottom
if (popoverRect.height > toWindowBottom) {
contentTop = activatorRect.top - popoverRect.height
if (contentRect.height > toWindowBottom) {
contentTop = activatorRect.top - contentRect.height
suggesetedTransfromOrigin = 'bottom left'
} else {
contentTop = activatorRect.top + activatorRect.height
@ -40,10 +40,10 @@ export default function calcPlacementTransform (placement, activatorRect, popove
contentLeft = activatorRect.left
} else if (placement === 'bottom-end') {
contentTop = activatorRect.top + activatorRect.height
contentLeft = activatorRect.left + activatorRect.width - popoverRect.width
contentLeft = activatorRect.left + activatorRect.width - contentRect.width
} else {
contentTop = activatorRect.top + activatorRect.height
contentLeft = activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2
contentLeft = activatorRect.left + activatorRect.width / 2 - contentRect.width / 2
}
/**
* We could also change the position using transform.
@ -51,5 +51,5 @@ export default function calcPlacementTransform (placement, activatorRect, popove
* However, I found that the dom delay is very serious.
* So I decide to use left and top for now.
*/
return [`left: ${contentLeft}px; top: ${contentTop}px;`, suggesetedTransfromOrigin]
return [{ left: `${contentLeft}px`, top: `${contentTop}px` }, suggesetedTransfromOrigin]
}

View File

@ -0,0 +1,52 @@
// class MinHeap {
// }
class ZIndexManager {
constructor () {
console.debug('[ZIndexManager]: Ctor called')
this.elementZIndex = new Map()
this.nextZIndex = 2000
}
get elementCount () {
return this.elementZIndex.size
}
registerElement (el) {
console.debug('[ZIndexManager.registerElement]: called')
if (this.elementZIndex.has(el)) {
console.debug('[ZIndexManager.registerElement]: do not register duplicate element')
} else {
console.debug('[ZIndexManager.registerElement]: successfully register', el)
el.style.zIndex = this.nextZIndex
this.elementZIndex.set(el, this.nextZIndex)
this.nextZIndex++
}
}
setNewZIndex (el) {
console.debug('[ZIndexManager.setNewZIndex]: called')
if (this.elementZIndex.has(el)) {
console.debug('[ZIndexManager.setNewZIndex]: successfully set z-index on', el, `(z-index: ${this.nextZIndex})`)
const currentZIndex = this.elementZIndex.get(el)
if (currentZIndex + 1 === this.nextZIndex) return
el.style.zIndex = this.nextZIndex
this.elementZIndex.set(el, this.nextZIndex)
this.nextZIndex++
} else {
console.debug('[ZIndexManager.setNewZIndex]: element not found, please register it first')
}
}
unregisterElement (el) {
console.debug('[ZIndexManager.unregisterElement]: called')
if (this.elementZIndex.has(el)) {
console.debug('[ZIndexManager.unregisterElement]: successfully delete', el)
this.elementZIndex.delete(el)
} else {
console.log('[ZIndexManager.unregisterElement]: element not found')
}
if (!this.elementCount) {
this.nextZIndex = 2000
}
}
}
export default new ZIndexManager()

Some files were not shown because too many files have changed in this diff Show More