wave-ui 2.45.1 → 2.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wave-ui.cjs.js +1 -1
- package/dist/wave-ui.css +1 -1
- package/dist/wave-ui.es.js +1912 -1663
- package/dist/wave-ui.umd.js +1 -1
- package/package.json +4 -4
- package/src/wave-ui/components/index.js +1 -1
- package/src/wave-ui/components/w-dialog.vue +1 -1
- package/src/wave-ui/components/w-drawer.vue +2 -0
- package/src/wave-ui/components/w-icon.vue +1 -0
- package/src/wave-ui/components/w-image.vue +4 -2
- package/src/wave-ui/components/w-input.vue +1 -1
- package/src/wave-ui/components/w-table.vue +25 -7
- package/src/wave-ui/components/w-tree.vue +294 -0
- package/src/wave-ui/core.js +3 -3
- package/src/wave-ui/scss/_colors.scss +66 -15
- package/src/wave-ui/utils/colors.js +229 -190
- package/src/wave-ui/utils/dynamic-css.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.47.0",
|
|
4
4
|
"description": "An emerging UI framework for Vue.js (2 & 3) with only the bright side. :sunny:",
|
|
5
5
|
"author": "Antoni Andre <antoniandre.web@gmail.com>",
|
|
6
6
|
"homepage": "https://antoniandre.github.io/wave-ui",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"lint": "vite lint"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@babel/core": "^7.20.
|
|
51
|
+
"@babel/core": "^7.20.5",
|
|
52
52
|
"@babel/eslint-parser": "^7.19.1",
|
|
53
53
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
54
54
|
"@mdi/font": "^5.9.55",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"autoprefixer": "^10.4.13",
|
|
58
58
|
"axios": "^0.25.0",
|
|
59
59
|
"eslint": "^7.32.0",
|
|
60
|
-
"eslint-plugin-vue": "^9.
|
|
60
|
+
"eslint-plugin-vue": "^9.8.0",
|
|
61
61
|
"font-awesome": "^4.7.0",
|
|
62
62
|
"gsap": "^3.11.3",
|
|
63
63
|
"ionicons": "^4.6.3",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"simple-syntax-highlighter": "^2.2.5",
|
|
70
70
|
"splitpanes": "^3.1.5",
|
|
71
71
|
"standard": "^17.0.0",
|
|
72
|
-
"vite": "^3.2.
|
|
72
|
+
"vite": "^3.2.5",
|
|
73
73
|
"vue": "^3.2.45",
|
|
74
74
|
"vue-router": "^4.1.6",
|
|
75
75
|
"vueperslides": "^3.5.1",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Keep all the `.vue` extensions for Vite & Rollup.
|
|
2
1
|
export { default as WAccordion } from './w-accordion.vue'
|
|
3
2
|
export { default as WAlert } from './w-alert.vue'
|
|
4
3
|
export { default as WApp } from './w-app.vue'
|
|
@@ -49,3 +48,4 @@ export { default as WTransitionScaleFade } from './transitions/w-transition-scal
|
|
|
49
48
|
export { default as WTransitionSlide } from './transitions/w-transition-slide.vue'
|
|
50
49
|
export { default as WTransitionSlideFade } from './transitions/w-transition-slide-fade.vue'
|
|
51
50
|
export { default as WTransitionTwist } from './transitions/w-transition-twist.vue'
|
|
51
|
+
export { default as WTree } from './w-tree.vue'
|
|
@@ -76,6 +76,7 @@ export default {
|
|
|
76
76
|
absolute: { type: Boolean },
|
|
77
77
|
overlayColor: { type: String },
|
|
78
78
|
overlayOpacity: { type: [Number, String, Boolean] },
|
|
79
|
+
drawerClass: { type: String },
|
|
79
80
|
tag: { type: String, default: 'aside' }
|
|
80
81
|
},
|
|
81
82
|
|
|
@@ -125,6 +126,7 @@ export default {
|
|
|
125
126
|
},
|
|
126
127
|
drawerClasses () {
|
|
127
128
|
return {
|
|
129
|
+
[this.drawerClass]: true,
|
|
128
130
|
[this.color]: this.color,
|
|
129
131
|
[`${this.bgColor}--bg`]: this.bgColor,
|
|
130
132
|
'w-drawer--open': !!this.showDrawer,
|
|
@@ -128,6 +128,7 @@ export default {
|
|
|
128
128
|
.w-button.size--lg &, .w-alert.size--lg & {font-size: round(1.7 * $base-font-size);}
|
|
129
129
|
.w-button.size--xl &, .w-alert.size--xl & {font-size: 2 * $base-font-size;}
|
|
130
130
|
|
|
131
|
+
&:before {transition: transform $transition-duration;}
|
|
131
132
|
&--spin:before {animation: w-icon--spin 2s infinite linear;}
|
|
132
133
|
&--spin-a:before {animation: w-icon--spin-a 2s infinite linear;}
|
|
133
134
|
&--rotate45:before {transform: rotate(45deg);}
|
|
@@ -9,7 +9,7 @@ component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperS
|
|
|
9
9
|
:src="tag === 'img' ? imgSrc : null")
|
|
10
10
|
.w-image__loader(v-if="!noSpinner && loading")
|
|
11
11
|
slot(v-if="$slots.loading" name="loading")
|
|
12
|
-
w-progress(v-else circle indeterminate)
|
|
12
|
+
w-progress(v-else circle indeterminate v-bind="spinnerColor ? { color: spinnerColor } : {}")
|
|
13
13
|
component.w-image__content(v-if="$slots.default" :is="wrapperTag" :class="contentClass")
|
|
14
14
|
slot
|
|
15
15
|
</template>
|
|
@@ -22,9 +22,10 @@ component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperS
|
|
|
22
22
|
* - adaptive size: given ratio + width 100% (use bg)
|
|
23
23
|
* - adaptive size: given ratio + height 100% (use bg)
|
|
24
24
|
* - adaptive & locked size: given width or height and using <img>
|
|
25
|
+
*
|
|
26
|
+
* @todo handle figure, captions, srcset, webp.
|
|
25
27
|
**/
|
|
26
28
|
|
|
27
|
-
// @todo handle figure, captions, srcset, webp.
|
|
28
29
|
import { consoleWarn } from '../utils/console'
|
|
29
30
|
|
|
30
31
|
export default {
|
|
@@ -40,6 +41,7 @@ export default {
|
|
|
40
41
|
fixed: { type: Boolean },
|
|
41
42
|
contain: { type: Boolean },
|
|
42
43
|
noSpinner: { type: Boolean },
|
|
44
|
+
spinnerColor: { type: String },
|
|
43
45
|
fallback: { type: String },
|
|
44
46
|
transition: { type: String, default: 'fade' },
|
|
45
47
|
contentClass: { type: [String, Array, Object] }
|
|
@@ -38,11 +38,16 @@
|
|
|
38
38
|
v-if="i < headers.length - 1 && resizableColumns"
|
|
39
39
|
:class="{ 'w-table__col-resizer--hover': colResizing.hover === i, 'w-table__col-resizer--active': colResizing.columnIndex === i }"
|
|
40
40
|
@click.stop)
|
|
41
|
+
//- Progress bar only.
|
|
42
|
+
w-transition-fade
|
|
43
|
+
tr.w-table__progress-bar(v-if="loading === 'header'")
|
|
44
|
+
td(:colspan="headers.length")
|
|
45
|
+
w-progress(tile)
|
|
41
46
|
|
|
42
47
|
//- Table body.
|
|
43
48
|
tbody
|
|
44
|
-
//- Progress bar.
|
|
45
|
-
tr.w-table__progress-bar(v-if="loading")
|
|
49
|
+
//- Progress bar & loading text.
|
|
50
|
+
tr.w-table__progress-bar(v-if="loading === true")
|
|
46
51
|
td(:colspan="headers.length")
|
|
47
52
|
w-progress(tile)
|
|
48
53
|
.w-table__loading-text
|
|
@@ -53,7 +58,7 @@
|
|
|
53
58
|
slot(name="no-data") No data to show.
|
|
54
59
|
|
|
55
60
|
//- Normal rows.
|
|
56
|
-
template(v-
|
|
61
|
+
template(v-if="tableItems.length && loading !== true")
|
|
57
62
|
template(v-for="(item, i) in sortedItems" :key="i")
|
|
58
63
|
//- Fully custom tr (`item` slot).
|
|
59
64
|
slot(
|
|
@@ -150,7 +155,7 @@ export default {
|
|
|
150
155
|
fixedLayout: { type: Boolean },
|
|
151
156
|
fixedHeaders: { type: Boolean },
|
|
152
157
|
fixedFooter: { type: Boolean },
|
|
153
|
-
loading: { type: Boolean },
|
|
158
|
+
loading: { type: [Boolean, String] }, // Bool or 'header' to only display the bar in the header.
|
|
154
159
|
// Allow single sort: `+id`, or multiple in an array like: ['+id', '-firstName'].
|
|
155
160
|
sort: { type: [String, Array] },
|
|
156
161
|
|
|
@@ -188,6 +193,7 @@ export default {
|
|
|
188
193
|
uidKey: { type: String, default: 'id' },
|
|
189
194
|
|
|
190
195
|
filter: { type: Function },
|
|
196
|
+
sortFunction: { type: Function },
|
|
191
197
|
mobileBreakpoint: { type: Number, default: 0 },
|
|
192
198
|
resizableColumns: { type: Boolean }
|
|
193
199
|
},
|
|
@@ -232,7 +238,7 @@ export default {
|
|
|
232
238
|
},
|
|
233
239
|
|
|
234
240
|
sortedItems () {
|
|
235
|
-
if (!this.activeSorting.length) return this.filteredItems
|
|
241
|
+
if (!this.activeSorting.length || this.sortFunction) return this.filteredItems
|
|
236
242
|
|
|
237
243
|
// Only sort with 1 key for now, may handle more later.
|
|
238
244
|
const sortKey1 = this.activeSorting[0].replace(/^[+-]/, '')
|
|
@@ -313,15 +319,18 @@ export default {
|
|
|
313
319
|
]
|
|
314
320
|
},
|
|
315
321
|
|
|
316
|
-
sortTable (header) {
|
|
322
|
+
async sortTable (header) {
|
|
317
323
|
const alreadySortingThis = this.activeSortingKeys[header.key]
|
|
318
324
|
if (alreadySortingThis && this.activeSortingKeys[header.key] === '-') {
|
|
319
325
|
this.activeSorting = []
|
|
320
|
-
return this.$emit('update:sort')
|
|
321
326
|
}
|
|
322
327
|
else this.activeSorting[0] = (alreadySortingThis ? '-' : '+') + header.key
|
|
323
328
|
|
|
324
329
|
this.$emit('update:sort', this.activeSorting)
|
|
330
|
+
|
|
331
|
+
if (typeof this.sortFunction === 'function') {
|
|
332
|
+
await this.sortFunction(this.activeSorting)
|
|
333
|
+
}
|
|
325
334
|
},
|
|
326
335
|
|
|
327
336
|
doSelectRow (item, index) {
|
|
@@ -549,6 +558,8 @@ $tr-border-top: 1px;
|
|
|
549
558
|
|
|
550
559
|
// Table headers.
|
|
551
560
|
// ------------------------------------------------------
|
|
561
|
+
thead {position: relative;}
|
|
562
|
+
|
|
552
563
|
&__header {padding: $base-increment;}
|
|
553
564
|
&__header--resizable {
|
|
554
565
|
overflow: hidden;
|
|
@@ -628,6 +639,12 @@ $tr-border-top: 1px;
|
|
|
628
639
|
|
|
629
640
|
// Progress bar when loading.
|
|
630
641
|
&__progress-bar:nth-child(odd) {background: none;}
|
|
642
|
+
thead .w-progress {
|
|
643
|
+
position: absolute;
|
|
644
|
+
bottom: 0;
|
|
645
|
+
left: 0;
|
|
646
|
+
right: 0;
|
|
647
|
+
}
|
|
631
648
|
&__progress-bar td {padding: 0;height: 1px;}
|
|
632
649
|
@-moz-document url-prefix() {
|
|
633
650
|
&__progress-bar td {height: 100%;}
|
|
@@ -754,6 +771,7 @@ $tr-border-top: 1px;
|
|
|
754
771
|
|
|
755
772
|
.w-table__progress-bar {
|
|
756
773
|
display: table-row;
|
|
774
|
+
|
|
757
775
|
td {display: table-cell;}
|
|
758
776
|
td:before {display: none;}
|
|
759
777
|
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
ul.w-tree(:class="classes")
|
|
3
|
+
li.w-tree__item(
|
|
4
|
+
v-for="(item, i) in currentDepthItems"
|
|
5
|
+
:key="i"
|
|
6
|
+
:class="itemClasses(item)")
|
|
7
|
+
.w-tree__item-label(
|
|
8
|
+
@click="!disabled && onLabelClick(item, $event)"
|
|
9
|
+
@keydown="!disabled && onLabelKeydown(item, $event)"
|
|
10
|
+
:tabindex="!disabled && (item.children || item.branch || selectable) && !(unexpandableEmpty && !item.children) ? 0 : null")
|
|
11
|
+
w-button.w-tree__item-expand(
|
|
12
|
+
v-if="(item.children || item.branch) && ((expandOpenIcon && item.open) || expandIcon) && !(unexpandableEmpty && !item.children)"
|
|
13
|
+
color="inherit"
|
|
14
|
+
:icon="(item.open && expandOpenIcon) || expandIcon"
|
|
15
|
+
:icon-props="{ rotate90a: !item.open }"
|
|
16
|
+
:tabindex="-1"
|
|
17
|
+
:disabled="disabled"
|
|
18
|
+
text
|
|
19
|
+
sm)
|
|
20
|
+
slot(name="item-label" :item="item.originalItem" :depth="depth" :open="item.open")
|
|
21
|
+
w-icon(v-if="itemIcon(item)" class="w-tree__item-icon") {{ itemIcon(item) }}
|
|
22
|
+
span {{ item.label }}
|
|
23
|
+
span.ml1(v-if="counts && (item.children || item.branch)").
|
|
24
|
+
({{ item.originalItem.children?.length || 0 }})
|
|
25
|
+
component(
|
|
26
|
+
:is="noTransition ? 'div' : 'w-transition-expand'"
|
|
27
|
+
:y="!noTransition || null"
|
|
28
|
+
@after-enter="$emit('open', { item: item.originalItem, open: item.open, depth })"
|
|
29
|
+
@after-leave="$emit('close', { item: item.originalItem, open: item.open, depth })")
|
|
30
|
+
w-tree(
|
|
31
|
+
v-if="item.children && item.open"
|
|
32
|
+
v-bind="$props"
|
|
33
|
+
:depth="depth + 1"
|
|
34
|
+
:data="item.originalItem.children"
|
|
35
|
+
@before-open="$emit('before-open', $event)"
|
|
36
|
+
@open="$emit('open', $event)"
|
|
37
|
+
@before-close="$emit('before-close', $event)"
|
|
38
|
+
@close="$emit('close', $event)"
|
|
39
|
+
@click="$emit('click', $event)"
|
|
40
|
+
@select="$emit('select', $event)"
|
|
41
|
+
@update:model-value="$emit('update:model-value', $event)")
|
|
42
|
+
template(#item-label="{ item, depth, open }")
|
|
43
|
+
slot(name="item-label" :item="item" :depth="depth" :open="open")
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script>
|
|
47
|
+
/**
|
|
48
|
+
* @todo things to support:
|
|
49
|
+
* - items routes
|
|
50
|
+
* - icon per item
|
|
51
|
+
* - left border?
|
|
52
|
+
**/
|
|
53
|
+
|
|
54
|
+
export default {
|
|
55
|
+
name: 'w-tree',
|
|
56
|
+
props: {
|
|
57
|
+
modelValue: { type: [Object, Array] },
|
|
58
|
+
data: { type: [Object, Array], required: true },
|
|
59
|
+
depth: { type: Number, default: 0 },
|
|
60
|
+
branchClass: { type: String },
|
|
61
|
+
leafClass: { type: String },
|
|
62
|
+
branchIcon: { type: String },
|
|
63
|
+
branchOpenIcon: { type: String },
|
|
64
|
+
leafIcon: { type: String },
|
|
65
|
+
expandIcon: { type: [Boolean, String], default: 'wi-triangle-down' },
|
|
66
|
+
expandOpenIcon: { type: [Boolean, String] },
|
|
67
|
+
expandAll: { type: Boolean },
|
|
68
|
+
unexpandableEmpty: { type: Boolean },
|
|
69
|
+
disabled: { type: Boolean },
|
|
70
|
+
noTransition: { type: Boolean },
|
|
71
|
+
selectable: { type: Boolean },
|
|
72
|
+
// By default it only reacts to items count change (added or deleted items) not property of items change.
|
|
73
|
+
depthReactivity: { type: Boolean },
|
|
74
|
+
counts: { type: Boolean }
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
emits: ['update:model-value', 'before-open', 'open', 'before-close', 'close', 'click', 'select'],
|
|
78
|
+
|
|
79
|
+
data: () => ({
|
|
80
|
+
currentDepthItems: [], // A clone of the data prop with additional info per item.
|
|
81
|
+
dataPropUnwatch: null // Holds the unwatch handler of the data prop.
|
|
82
|
+
}),
|
|
83
|
+
|
|
84
|
+
computed: {
|
|
85
|
+
classes () {
|
|
86
|
+
return {
|
|
87
|
+
[`w-tree--depth${this.depth}`]: true,
|
|
88
|
+
'w-tree--expand-icon': this.expandIcon && !this.depth,
|
|
89
|
+
'w-tree--disabled': this.disabled && !this.depth,
|
|
90
|
+
'w-tree--no-expand-button': !this.expandIcon
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
methods: {
|
|
96
|
+
// From data watcher, retain the oldItems open state.
|
|
97
|
+
updateCurrentDepthTree (items, oldItems = []) {
|
|
98
|
+
this.currentDepthItems = []
|
|
99
|
+
|
|
100
|
+
items.forEach((item, i) => {
|
|
101
|
+
this.currentDepthItems.push({
|
|
102
|
+
originalItem: item, // Store the original item to return it on event emits.
|
|
103
|
+
_uid: this.depth.toString() + (i + 1),
|
|
104
|
+
label: item.label,
|
|
105
|
+
children: !!item.children, // The children tree remains available in originalItem.
|
|
106
|
+
branch: item.branch,
|
|
107
|
+
depth: this.depth,
|
|
108
|
+
open: oldItems[i]?.open || false
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Expand/collapse the given tree item when possible (not disabled, has children).
|
|
115
|
+
*
|
|
116
|
+
* @param {Object} item the item to expand.
|
|
117
|
+
* @param {Boolean|Undefined} open when a boolean is received, force a state (open or close).
|
|
118
|
+
*/
|
|
119
|
+
expandDepth (item, open) {
|
|
120
|
+
if (typeof open === 'boolean') item.open = open
|
|
121
|
+
else item.open = !item.open
|
|
122
|
+
|
|
123
|
+
const emitParams = { item: item.originalItem, open: item.open, depth: this.depth }
|
|
124
|
+
|
|
125
|
+
this.$emit(item.open ? 'before-open' : 'before-close', emitParams)
|
|
126
|
+
|
|
127
|
+
if (!this.unexpandableEmpty && !item.children) {
|
|
128
|
+
this.$emit(item.open ? 'open' : 'close', emitParams)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return true // Just to chain instructions.
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
onLabelClick (item, e) {
|
|
135
|
+
this.$emit('click', { item: item.originalItem, depth: this.depth, e })
|
|
136
|
+
if (item.children || (item.branch && !this.unexpandableEmpty)) this.expandDepth(item)
|
|
137
|
+
|
|
138
|
+
if (this.selectable) this.emitItemSelection(item, e)
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
emitItemSelection (item, e) {
|
|
142
|
+
const emitParams = { item: item.originalItem, depth: this.depth, e }
|
|
143
|
+
if (item.children || (item.branch && !this.unexpandableEmpty)) {
|
|
144
|
+
emitParams.open = item.open
|
|
145
|
+
}
|
|
146
|
+
this.$emit('update:model-value', emitParams)
|
|
147
|
+
this.$emit('select', emitParams)
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
onLabelKeydown (item, e) {
|
|
151
|
+
// Keys: 13 enter, 32 space, 37 arrow left, 38 arrow up, 39 arrow right, 40 arrow down.
|
|
152
|
+
if (!(e.metaKey || e.ctrlKey || e.altKey || e.shiftKey) && [13, 32, 37, 38, 39, 40].includes(e.which)) {
|
|
153
|
+
if (item.children || item.branch) {
|
|
154
|
+
if ([13, 32].includes(e.which)) this.expandDepth(item) && e.preventDefault()
|
|
155
|
+
else if (e.which === 37) this.expandDepth(item, false) && e.preventDefault()
|
|
156
|
+
else if (e.which === 39) this.expandDepth(item, true) && e.preventDefault()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// On arrow up or down, focus the prev or next item.
|
|
160
|
+
if ([38, 40].includes(e.which)) {
|
|
161
|
+
const treeRoot = this.$el.closest('.w-tree--depth0')
|
|
162
|
+
const treeTabbableItems = treeRoot.querySelectorAll('.w-tree__item-label[tabindex="0"]')
|
|
163
|
+
const currLabel = e.target.closest('.w-tree__item-label')
|
|
164
|
+
const indexModifier = e.which === 38 ? -1 : 1;
|
|
165
|
+
|
|
166
|
+
([...treeTabbableItems]).some((item, i) => {
|
|
167
|
+
if (item.isSameNode(currLabel)) {
|
|
168
|
+
treeTabbableItems[i + indexModifier] && treeTabbableItems[i + indexModifier].focus()
|
|
169
|
+
return true // Break the loop.
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this.selectable) this.emitItemSelection(item, e)
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Returns the previous sibling matching the given selector, or false if not found.
|
|
180
|
+
*
|
|
181
|
+
* @param {Object} node the DOM node to find sibling for.
|
|
182
|
+
* @param {String} selector any valid DOM selector to match the siblings.
|
|
183
|
+
*/
|
|
184
|
+
getPreviousSibling (node, selector) {
|
|
185
|
+
while (selector && (node = node.previousElementSibling)) {
|
|
186
|
+
if (node.matches(selector)) return node
|
|
187
|
+
}
|
|
188
|
+
return false
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Returns the next sibling matching the given selector, or false if not found.
|
|
193
|
+
*
|
|
194
|
+
* @param {Object} node the DOM node to find sibling for.
|
|
195
|
+
* @param {String} selector any valid DOM selector to match the siblings.
|
|
196
|
+
*/
|
|
197
|
+
getNextSibling (node, selector) {
|
|
198
|
+
while (selector && (node = node.nextElementSibling)) {
|
|
199
|
+
if (node.matches(selector)) return node
|
|
200
|
+
}
|
|
201
|
+
return false
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
focusTreeItem (liNode) {
|
|
205
|
+
liNode && liNode.querySelector('.w-tree__item-label').focus()
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
itemIcon (item) {
|
|
209
|
+
return (
|
|
210
|
+
item.originalItem.icon ||
|
|
211
|
+
(!item.children && !item.branch && this.leafIcon) ||
|
|
212
|
+
((item.children || item.branch) && ((item.open && this.branchOpenIcon) || this.branchIcon))
|
|
213
|
+
)
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
itemClasses (item) {
|
|
217
|
+
return {
|
|
218
|
+
[item.children || item.branch ? 'w-tree__item--branch' : 'w-tree__item--leaf']: true,
|
|
219
|
+
'w-tree__item--empty': item.branch && !item.children,
|
|
220
|
+
'w-tree__item--unexpandable': item.branch && !item.children && this.unexpandableEmpty
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
created () {
|
|
226
|
+
this.updateCurrentDepthTree(this.data)
|
|
227
|
+
this.dataPropUnwatch = this.$watch(
|
|
228
|
+
'data',
|
|
229
|
+
// The open property of each item has to be retained from this.currentDepthItems in order to stay
|
|
230
|
+
// in the same state after DOM repaint.
|
|
231
|
+
items => this.updateCurrentDepthTree(items, this.currentDepthItems),
|
|
232
|
+
{ deep: !!this.depthReactivity } // Deep watching is more resource consuming. Only enable on user demand.
|
|
233
|
+
)
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
unmounted () {
|
|
237
|
+
this.dataPropUnwatch()
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
</script>
|
|
241
|
+
|
|
242
|
+
<style lang="scss">
|
|
243
|
+
$expand-icon-size: 20px;
|
|
244
|
+
|
|
245
|
+
.w-tree {
|
|
246
|
+
margin: 0;
|
|
247
|
+
|
|
248
|
+
// Tree items.
|
|
249
|
+
// ------------------------------------------------------
|
|
250
|
+
&__item {list-style-type: none;}
|
|
251
|
+
&__item--branch {}
|
|
252
|
+
&__item--leaf {margin-left: $base-increment * 5 + 2px;}
|
|
253
|
+
&--no-expand-button &__item--leaf {margin-left: 0;}
|
|
254
|
+
|
|
255
|
+
// Tree item label.
|
|
256
|
+
// ------------------------------------------------------
|
|
257
|
+
&__item-label {
|
|
258
|
+
position: relative;
|
|
259
|
+
display: inline-flex;
|
|
260
|
+
align-items: center;
|
|
261
|
+
|
|
262
|
+
&:before {
|
|
263
|
+
content: '';
|
|
264
|
+
position: absolute;
|
|
265
|
+
top: -1px;
|
|
266
|
+
bottom: -1px;
|
|
267
|
+
left: - $base-increment + 2px;
|
|
268
|
+
right: - $base-increment - 2px;
|
|
269
|
+
border-radius: $border-radius;
|
|
270
|
+
}
|
|
271
|
+
&:focus:before {background-color: rgba($primary, 0.1);}
|
|
272
|
+
}
|
|
273
|
+
&__item--leaf &__item-label:before {
|
|
274
|
+
left: - $base-increment;
|
|
275
|
+
right: - $base-increment;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
&__item-expand {margin-right: 2px;}
|
|
279
|
+
|
|
280
|
+
&__item--branch > &__item-label {cursor: pointer;}
|
|
281
|
+
&__item--unexpandable > &__item-label {
|
|
282
|
+
margin-left: $expand-icon-size + 2px;
|
|
283
|
+
cursor: auto;
|
|
284
|
+
}
|
|
285
|
+
&--disabled &__item-label {cursor: auto;}
|
|
286
|
+
&--disabled &__item--branch > &__item-label {opacity: 0.5;}
|
|
287
|
+
|
|
288
|
+
&__item-icon {margin-right: $base-increment;}
|
|
289
|
+
|
|
290
|
+
// Recursive children.
|
|
291
|
+
// ------------------------------------------------------
|
|
292
|
+
.w-tree {margin-left: $base-increment * 5;}
|
|
293
|
+
}
|
|
294
|
+
</style>
|
package/src/wave-ui/core.js
CHANGED
|
@@ -4,9 +4,9 @@ import NotificationManager from './utils/notification-manager'
|
|
|
4
4
|
import colors from './utils/colors'
|
|
5
5
|
// import * as directives from './directives'
|
|
6
6
|
|
|
7
|
-
const shadeColor = (
|
|
8
|
-
return '#' +
|
|
9
|
-
.map(x => (x =+ `0x${x}` +
|
|
7
|
+
const shadeColor = (color, amount) => {
|
|
8
|
+
return '#' + color.slice(1).match(/../g)
|
|
9
|
+
.map(x => (x =+ `0x${x}` + amount, x < 0 ? 0 : ( x > 255 ? 255 : x)).toString(16).padStart(2, 0))
|
|
10
10
|
.join('')
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -41,28 +41,79 @@
|
|
|
41
41
|
.#{$label}--bg {background-color: $color;}
|
|
42
42
|
.#{$label} {color: $color;}
|
|
43
43
|
|
|
44
|
-
@for $i from 1 through
|
|
45
|
-
$light-increment:
|
|
44
|
+
@for $i from 1 through 6 {
|
|
45
|
+
$light-increment: 7.5;
|
|
46
|
+
$light-offset: 0;
|
|
47
|
+
$dark-increment: 6.2;
|
|
46
48
|
// Some color shades need bigger or smaller increments to end up with the same scale.
|
|
47
49
|
@if $label == 'deep-orange' {
|
|
48
|
-
$light-increment:
|
|
50
|
+
$light-increment: 6.4;
|
|
49
51
|
}
|
|
50
|
-
@if $label == '
|
|
51
|
-
$light-increment: 8.3;
|
|
52
|
+
@if $label == 'orange' {
|
|
52
53
|
}
|
|
53
|
-
@if $label == '
|
|
54
|
-
$light-increment:
|
|
54
|
+
@else if $label == 'green' {
|
|
55
|
+
$light-increment: 7.6;
|
|
56
|
+
$dark-increment: 5.7;
|
|
55
57
|
}
|
|
56
|
-
@if $label == '
|
|
57
|
-
$light-increment: 9;
|
|
58
|
+
@else if $label == 'amber' {
|
|
58
59
|
}
|
|
59
|
-
@if $label == '
|
|
60
|
-
$light-increment:
|
|
60
|
+
@else if $label == 'pink' {
|
|
61
|
+
$light-increment: 6.7;
|
|
62
|
+
$light-offset: -4;
|
|
61
63
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
@else if $label == 'red' {
|
|
65
|
+
$light-increment: 6.5;
|
|
66
|
+
$light-offset: -1;
|
|
67
|
+
}
|
|
68
|
+
@else if $label == 'indigo' {
|
|
69
|
+
$light-increment: 8;
|
|
70
|
+
$dark-increment: 5.7;
|
|
71
|
+
}
|
|
72
|
+
@else if $label == 'deep-purple' {
|
|
73
|
+
$light-increment: 8;
|
|
74
|
+
$dark-increment: 5.7;
|
|
75
|
+
}
|
|
76
|
+
@else if $label == 'light-blue' {
|
|
77
|
+
$light-increment: 7.8;
|
|
78
|
+
}
|
|
79
|
+
@else if $label == 'light-green' {
|
|
80
|
+
$light-increment: 6;
|
|
81
|
+
$light-offset: -5;
|
|
82
|
+
}
|
|
83
|
+
@else if $label == 'lime' {
|
|
84
|
+
$light-increment: 6.2;
|
|
85
|
+
$light-offset: -6;
|
|
86
|
+
}
|
|
87
|
+
@else if $label == 'yellow' {
|
|
88
|
+
$light-increment: 5.5;
|
|
89
|
+
$light-offset: -8;
|
|
90
|
+
}
|
|
91
|
+
@else if $label == 'purple' {
|
|
92
|
+
$light-increment: 6.5;
|
|
93
|
+
$light-offset: -8.5;
|
|
94
|
+
}
|
|
95
|
+
@else if $label == 'cyan' {
|
|
96
|
+
$light-increment: 9.4;
|
|
97
|
+
$light-offset: 6.5;
|
|
98
|
+
$dark-increment: 5.7;
|
|
99
|
+
}
|
|
100
|
+
@else if $label == 'teal' {
|
|
101
|
+
$light-increment: 9.6;
|
|
102
|
+
$light-offset: 5;
|
|
103
|
+
$dark-increment: 5.4;
|
|
104
|
+
}
|
|
105
|
+
@else if $label == 'blue' {
|
|
106
|
+
$light-increment: 6.8;
|
|
107
|
+
$dark-increment: 6.8;
|
|
108
|
+
}
|
|
109
|
+
@else if $label == 'brown' {
|
|
110
|
+
$light-increment: 8.8;
|
|
111
|
+
$dark-increment: 5;
|
|
112
|
+
}
|
|
113
|
+
.#{$label}-light#{$i}--bg {background-color: lighten($color, $light-increment * $i - $light-offset);}
|
|
114
|
+
.#{$label}-light#{$i} {color: lighten($color, $light-increment * $i - $light-offset);}
|
|
115
|
+
.#{$label}-dark#{$i}--bg {background-color: darken($color, $dark-increment * $i);}
|
|
116
|
+
.#{$label}-dark#{$i} {color: darken($color, $dark-increment * $i);}
|
|
66
117
|
}
|
|
67
118
|
}
|
|
68
119
|
}
|