wave-ui 2.46.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-ui",
3
- "version": "2.46.0",
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.2",
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.7.0",
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.3",
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'
@@ -123,7 +123,7 @@ export default {
123
123
  overflow: auto;
124
124
  background-color: #fff;
125
125
 
126
- .w-dialog--fullscreen & {
126
+ .w-dialog--fullscreen > & {
127
127
  flex: 1 1 auto;
128
128
  height: 100%;
129
129
  max-width: none;
@@ -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] }
@@ -457,7 +457,7 @@ $inactive-color: #777;
457
457
  &__input {
458
458
  width: 100%;
459
459
  height: 100%;
460
- font-size: inherit;
460
+ font: inherit;
461
461
  color: inherit;
462
462
  text-align: inherit;
463
463
  display: inline-flex;
@@ -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>
@@ -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 = (col, amt) => {
8
- return '#' + col.slice(1).match(/../g)
9
- .map(x => (x =+ `0x${x}` + amt, x < 0 ? 0 : ( x > 255 ? 255 : x)).toString(16).padStart(2, 0))
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 5 {
45
- $light-increment: 8;
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: 7;
50
+ $light-increment: 6.4;
49
51
  }
50
- @if $label == 'green' or $label == 'amber' {
51
- $light-increment: 8.3;
52
+ @if $label == 'orange' {
52
53
  }
53
- @if $label == 'pink' or $label == 'orange' {
54
- $light-increment: 8.5;
54
+ @else if $label == 'green' {
55
+ $light-increment: 7.6;
56
+ $dark-increment: 5.7;
55
57
  }
56
- @if $label == 'cyan' or $label == 'purple' or $label == 'deep-purple' or $label == 'indigo' or $label == 'light-blue' {
57
- $light-increment: 9;
58
+ @else if $label == 'amber' {
58
59
  }
59
- @if $label == 'teal' or $label == 'brown' {
60
- $light-increment: 10;
60
+ @else if $label == 'pink' {
61
+ $light-increment: 6.7;
62
+ $light-offset: -4;
61
63
  }
62
- .#{$label}-light#{$i}--bg {background-color: lighten($color, $light-increment * $i);}
63
- .#{$label}-light#{$i} {color: lighten($color, $light-increment * $i);}
64
- .#{$label}-dark#{$i}--bg {background-color: darken($color, 6 * $i);}
65
- .#{$label}-dark#{$i} {color: darken($color, 6 * $i);}
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
  }