wave-ui 2.47.0 → 3.0.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 +1920 -1638
- package/dist/wave-ui.umd.js +1 -1
- package/package.json +4 -3
- package/src/wave-ui/components/index.js +1 -0
- package/src/wave-ui/components/transitions/w-transition-expand.vue +26 -15
- package/src/wave-ui/components/w-accordion.vue +8 -2
- package/src/wave-ui/components/w-alert.vue +10 -4
- package/src/wave-ui/components/w-app.vue +2 -107
- package/src/wave-ui/components/w-badge.vue +7 -3
- package/src/wave-ui/components/w-button/button.vue +6 -2
- package/src/wave-ui/components/w-card.vue +14 -4
- package/src/wave-ui/components/w-checkbox.vue +15 -8
- package/src/wave-ui/components/w-confirm.vue +7 -2
- package/src/wave-ui/components/w-date-picker.vue +6 -0
- package/src/wave-ui/components/w-dialog.vue +9 -3
- package/src/wave-ui/components/w-divider.vue +9 -3
- package/src/wave-ui/components/w-drawer.vue +9 -3
- package/src/wave-ui/components/w-input.vue +4 -2
- package/src/wave-ui/components/w-list.vue +1 -1
- package/src/wave-ui/components/w-menu.vue +11 -4
- package/src/wave-ui/components/w-notification-manager.vue +18 -30
- package/src/wave-ui/components/w-notification.vue +7 -1
- package/src/wave-ui/components/w-progress.vue +2 -2
- package/src/wave-ui/components/w-radio.vue +8 -2
- package/src/wave-ui/components/w-rating.vue +11 -3
- package/src/wave-ui/components/w-scrollbar.vue +24 -0
- package/src/wave-ui/components/w-select.vue +18 -8
- package/src/wave-ui/components/w-slider.vue +13 -7
- package/src/wave-ui/components/w-steps.vue +14 -4
- package/src/wave-ui/components/w-switch.vue +14 -14
- package/src/wave-ui/components/w-table.vue +107 -16
- package/src/wave-ui/components/w-tabs/index.vue +8 -2
- package/src/wave-ui/components/w-tag.vue +15 -10
- package/src/wave-ui/components/w-textarea.vue +6 -2
- package/src/wave-ui/components/w-timeline.vue +18 -5
- package/src/wave-ui/components/w-toolbar.vue +8 -2
- package/src/wave-ui/components/w-tooltip.vue +10 -4
- package/src/wave-ui/components/w-tree.vue +57 -19
- package/src/wave-ui/core.js +117 -90
- package/src/wave-ui/scss/_base.scss +53 -2
- package/src/wave-ui/scss/_colors.scss +41 -17
- package/src/wave-ui/scss/_layout.scss +5 -12
- package/src/wave-ui/scss/_mixins.scss +24 -0
- package/src/wave-ui/scss/_variables.scss +100 -11
- package/src/wave-ui/utils/colors.js +60 -3
- package/src/wave-ui/utils/config.js +35 -11
- package/src/wave-ui/utils/dynamic-css.js +92 -30
- package/src/wave-ui/utils/notification-manager.js +39 -8
|
@@ -4,22 +4,27 @@ ul.w-tree(:class="classes")
|
|
|
4
4
|
v-for="(item, i) in currentDepthItems"
|
|
5
5
|
:key="i"
|
|
6
6
|
:class="itemClasses(item)")
|
|
7
|
-
.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
//- The keys `route` & `disabled` are always present in any currentDepthItems.
|
|
8
|
+
component.w-tree__item-label(
|
|
9
|
+
:is="!disabled && !item.disabled && item.route ? (!$router || hasExternalLink(item) ? 'a' : 'router-link') : 'div'"
|
|
10
|
+
v-bind="item.route && { [!$router || hasExternalLink(item) ? 'href' : 'to']: item.route }"
|
|
11
|
+
@click="!disabled && !item.disabled && onLabelClick(item, $event)"
|
|
12
|
+
@keydown="!disabled && !item.disabled && onLabelKeydown(item, $event)"
|
|
13
|
+
:tabindex="!disabled && !item.disabled && (item.children || item.branch || selectable) && !(unexpandableEmpty && !item.children) ? 0 : null")
|
|
14
|
+
//- @click.stop to not follow link if item is a link.
|
|
11
15
|
w-button.w-tree__item-expand(
|
|
12
16
|
v-if="(item.children || item.branch) && ((expandOpenIcon && item.open) || expandIcon) && !(unexpandableEmpty && !item.children)"
|
|
17
|
+
@click.stop="!disabled && !item.disabled && onLabelClick(item, $event)"
|
|
13
18
|
color="inherit"
|
|
14
19
|
:icon="(item.open && expandOpenIcon) || expandIcon"
|
|
15
20
|
:icon-props="{ rotate90a: !item.open }"
|
|
16
21
|
:tabindex="-1"
|
|
17
|
-
:disabled="disabled"
|
|
22
|
+
:disabled="disabled || item.disabled"
|
|
18
23
|
text
|
|
19
24
|
sm)
|
|
20
|
-
slot(name="item
|
|
21
|
-
w-icon(v-if="itemIcon(item)" class="w-tree__item-icon") {{ itemIcon(item) }}
|
|
22
|
-
span
|
|
25
|
+
slot(name="item" :item="item.originalItem" :depth="depth" :open="item.open")
|
|
26
|
+
w-icon(v-if="itemIcon(item)" class="w-tree__item-icon" :color="item.originalItem[itemIconColorKey] || iconColor") {{ itemIcon(item) }}
|
|
27
|
+
span(v-html="item.label")
|
|
23
28
|
span.ml1(v-if="counts && (item.children || item.branch)").
|
|
24
29
|
({{ item.originalItem.children?.length || 0 }})
|
|
25
30
|
component(
|
|
@@ -39,16 +44,15 @@ ul.w-tree(:class="classes")
|
|
|
39
44
|
@click="$emit('click', $event)"
|
|
40
45
|
@select="$emit('select', $event)"
|
|
41
46
|
@update:model-value="$emit('update:model-value', $event)")
|
|
42
|
-
template(#item
|
|
43
|
-
slot(name="item
|
|
47
|
+
template(#item="{ item, depth, open }")
|
|
48
|
+
slot(name="item" :item="item" :depth="depth" :open="open")
|
|
44
49
|
</template>
|
|
45
50
|
|
|
46
51
|
<script>
|
|
52
|
+
import { consoleWarn } from '../utils/console'
|
|
47
53
|
/**
|
|
48
|
-
* @todo
|
|
49
|
-
* -
|
|
50
|
-
* - icon per item
|
|
51
|
-
* - left border?
|
|
54
|
+
* @todo:
|
|
55
|
+
* - option to add a left border.
|
|
52
56
|
**/
|
|
53
57
|
|
|
54
58
|
export default {
|
|
@@ -70,8 +74,14 @@ export default {
|
|
|
70
74
|
noTransition: { type: Boolean },
|
|
71
75
|
selectable: { type: Boolean },
|
|
72
76
|
// By default it only reacts to items count change (added or deleted items) not property of items change.
|
|
73
|
-
|
|
74
|
-
counts: { type: Boolean }
|
|
77
|
+
deepReactivity: { type: Boolean },
|
|
78
|
+
counts: { type: Boolean },
|
|
79
|
+
itemIconKey: { type: String, default: 'icon' }, // Support a different icon per item.
|
|
80
|
+
iconColor: { type: String }, // Applies a color on all the label item icons.
|
|
81
|
+
itemIconColorKey: { type: String, default: 'iconColor' }, // Applies a specific color on each label item icons.
|
|
82
|
+
itemRouteKey: { type: String, default: 'route' }, // Uses a router link if the item has the `route` key.
|
|
83
|
+
itemDisabledKey: { type: String, default: 'disabled' }, // Disables the item click and selection.
|
|
84
|
+
itemOpenKey: { type: String, default: 'open' } // Open the item by default.
|
|
75
85
|
},
|
|
76
86
|
|
|
77
87
|
emits: ['update:model-value', 'before-open', 'open', 'before-close', 'close', 'click', 'select'],
|
|
@@ -97,6 +107,12 @@ export default {
|
|
|
97
107
|
updateCurrentDepthTree (items, oldItems = []) {
|
|
98
108
|
this.currentDepthItems = []
|
|
99
109
|
|
|
110
|
+
if (!Array.isArray(items) && typeof items !== 'object') {
|
|
111
|
+
return consoleWarn(`[w-tree] the tree items must be of type array or object, ${typeof items} received.`, items)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!Array.isArray(items)) items = [items]
|
|
115
|
+
|
|
100
116
|
items.forEach((item, i) => {
|
|
101
117
|
this.currentDepthItems.push({
|
|
102
118
|
originalItem: item, // Store the original item to return it on event emits.
|
|
@@ -104,8 +120,10 @@ export default {
|
|
|
104
120
|
label: item.label,
|
|
105
121
|
children: !!item.children, // The children tree remains available in originalItem.
|
|
106
122
|
branch: item.branch,
|
|
123
|
+
route: item[this.itemRouteKey],
|
|
124
|
+
disabled: item[this.itemDisabledKey],
|
|
107
125
|
depth: this.depth,
|
|
108
|
-
open: oldItems[i]?.open ||
|
|
126
|
+
open: !!(oldItems[i]?.open || this.expandAll || item[this.itemOpenKey])
|
|
109
127
|
})
|
|
110
128
|
})
|
|
111
129
|
},
|
|
@@ -132,6 +150,9 @@ export default {
|
|
|
132
150
|
},
|
|
133
151
|
|
|
134
152
|
onLabelClick (item, e) {
|
|
153
|
+
const route = item[this.itemRouteKey]
|
|
154
|
+
if (route && this.$router && !this.hasExternalLink(item)) e.preventDefault()
|
|
155
|
+
|
|
135
156
|
this.$emit('click', { item: item.originalItem, depth: this.depth, e })
|
|
136
157
|
if (item.children || (item.branch && !this.unexpandableEmpty)) this.expandDepth(item)
|
|
137
158
|
|
|
@@ -168,6 +189,7 @@ export default {
|
|
|
168
189
|
treeTabbableItems[i + indexModifier] && treeTabbableItems[i + indexModifier].focus()
|
|
169
190
|
return true // Break the loop.
|
|
170
191
|
}
|
|
192
|
+
return false
|
|
171
193
|
})
|
|
172
194
|
}
|
|
173
195
|
}
|
|
@@ -182,6 +204,7 @@ export default {
|
|
|
182
204
|
* @param {String} selector any valid DOM selector to match the siblings.
|
|
183
205
|
*/
|
|
184
206
|
getPreviousSibling (node, selector) {
|
|
207
|
+
// eslint-disable-next-line no-unmodified-loop-condition
|
|
185
208
|
while (selector && (node = node.previousElementSibling)) {
|
|
186
209
|
if (node.matches(selector)) return node
|
|
187
210
|
}
|
|
@@ -195,6 +218,7 @@ export default {
|
|
|
195
218
|
* @param {String} selector any valid DOM selector to match the siblings.
|
|
196
219
|
*/
|
|
197
220
|
getNextSibling (node, selector) {
|
|
221
|
+
// eslint-disable-next-line no-unmodified-loop-condition
|
|
198
222
|
while (selector && (node = node.nextElementSibling)) {
|
|
199
223
|
if (node.matches(selector)) return node
|
|
200
224
|
}
|
|
@@ -207,15 +231,20 @@ export default {
|
|
|
207
231
|
|
|
208
232
|
itemIcon (item) {
|
|
209
233
|
return (
|
|
210
|
-
item.originalItem.
|
|
234
|
+
item.originalItem[this.itemIconKey] ||
|
|
211
235
|
(!item.children && !item.branch && this.leafIcon) ||
|
|
212
236
|
((item.children || item.branch) && ((item.open && this.branchOpenIcon) || this.branchIcon))
|
|
213
237
|
)
|
|
214
238
|
},
|
|
215
239
|
|
|
240
|
+
hasExternalLink (item) {
|
|
241
|
+
return /^(https?:)?\/\/|mailto:|tel:/.test(item[this.itemRouteKey])
|
|
242
|
+
},
|
|
243
|
+
|
|
216
244
|
itemClasses (item) {
|
|
217
245
|
return {
|
|
218
246
|
[item.children || item.branch ? 'w-tree__item--branch' : 'w-tree__item--leaf']: true,
|
|
247
|
+
'w-tree__item--disabled': item[this.itemDisabledKey],
|
|
219
248
|
'w-tree__item--empty': item.branch && !item.children,
|
|
220
249
|
'w-tree__item--unexpandable': item.branch && !item.children && this.unexpandableEmpty
|
|
221
250
|
}
|
|
@@ -229,7 +258,7 @@ export default {
|
|
|
229
258
|
// The open property of each item has to be retained from this.currentDepthItems in order to stay
|
|
230
259
|
// in the same state after DOM repaint.
|
|
231
260
|
items => this.updateCurrentDepthTree(items, this.currentDepthItems),
|
|
232
|
-
{ deep: !!this.
|
|
261
|
+
{ deep: !!this.deepReactivity } // Deep watching is more resource consuming. Only enable on user demand.
|
|
233
262
|
)
|
|
234
263
|
},
|
|
235
264
|
|
|
@@ -258,6 +287,7 @@ $expand-icon-size: 20px;
|
|
|
258
287
|
position: relative;
|
|
259
288
|
display: inline-flex;
|
|
260
289
|
align-items: center;
|
|
290
|
+
user-select: none;
|
|
261
291
|
|
|
262
292
|
&:before {
|
|
263
293
|
content: '';
|
|
@@ -268,16 +298,24 @@ $expand-icon-size: 20px;
|
|
|
268
298
|
right: - $base-increment - 2px;
|
|
269
299
|
border-radius: $border-radius;
|
|
270
300
|
}
|
|
301
|
+
&:hover:before {background-color: rgba($primary, 0.05);}
|
|
271
302
|
&:focus:before {background-color: rgba($primary, 0.1);}
|
|
272
303
|
}
|
|
273
304
|
&__item--leaf &__item-label:before {
|
|
274
305
|
left: - $base-increment;
|
|
275
306
|
right: - $base-increment;
|
|
276
307
|
}
|
|
308
|
+
&__item--disabled &__item-label {opacity: 0.5;}
|
|
309
|
+
&__item--disabled &__item-label:before {display: none;}
|
|
277
310
|
|
|
278
311
|
&__item-expand {margin-right: 2px;}
|
|
279
312
|
|
|
280
313
|
&__item--branch > &__item-label {cursor: pointer;}
|
|
314
|
+
&__item--disabled > &__item-label {
|
|
315
|
+
color: $disabled-color;
|
|
316
|
+
cursor: not-allowed;
|
|
317
|
+
-webkit-tap-highlight-color: transparent;
|
|
318
|
+
}
|
|
281
319
|
&__item--unexpandable > &__item-label {
|
|
282
320
|
margin-left: $expand-icon-size + 2px;
|
|
283
321
|
cursor: auto;
|
package/src/wave-ui/core.js
CHANGED
|
@@ -1,52 +1,73 @@
|
|
|
1
1
|
import { reactive, inject } from 'vue'
|
|
2
|
-
import
|
|
3
|
-
import NotificationManager from './utils/notification-manager'
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import { mergeConfig } from './utils/config'
|
|
3
|
+
import { injectNotifManagerInDOM, NotificationManager } from './utils/notification-manager'
|
|
4
|
+
import { colorPalette, generateColorShades, flattenColors } from './utils/colors'
|
|
5
|
+
import { injectColorsCSSInDOM, injectCSSInDOM } from './utils/dynamic-css'
|
|
6
|
+
import './scss/index.scss'
|
|
7
|
+
|
|
8
|
+
let mounted = false
|
|
9
|
+
const detectOSDarkMode = $waveui => {
|
|
10
|
+
const matchMedia = window.matchMedia('(prefers-color-scheme: dark)')
|
|
11
|
+
$waveui.preferredTheme = matchMedia.matches ? 'dark' : 'light'
|
|
12
|
+
$waveui.switchTheme($waveui.preferredTheme)
|
|
13
|
+
|
|
14
|
+
matchMedia.addEventListener('change', event => {
|
|
15
|
+
$waveui.preferredTheme = event.matches ? 'dark' : 'light'
|
|
16
|
+
$waveui.switchTheme($waveui.preferredTheme)
|
|
17
|
+
})
|
|
11
18
|
}
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Inject presets into a Vue component props defaults before its registration into the app.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} component the Vue component to inject presets into.
|
|
24
|
+
* @param {Object} presets the presets to inject. E.g. `{ bgColor: 'green' }`.
|
|
25
|
+
*/
|
|
26
|
+
const injectPresets = (component, presets) => {
|
|
27
|
+
for (const preset in presets) {
|
|
28
|
+
component.props[preset].default = presets[preset]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
18
31
|
|
|
19
32
|
export default class WaveUI {
|
|
20
|
-
static
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
static #registered = false
|
|
34
|
+
|
|
35
|
+
// Exposed as a global object and also `app.provide`d.
|
|
36
|
+
// Accessible from this.$waveui, or inject('$waveui').
|
|
37
|
+
$waveui = {
|
|
38
|
+
breakpoint: {
|
|
39
|
+
name: '',
|
|
40
|
+
xs: false,
|
|
41
|
+
sm: false,
|
|
42
|
+
md: false,
|
|
43
|
+
lg: false,
|
|
44
|
+
xl: false,
|
|
45
|
+
width: null
|
|
46
|
+
},
|
|
47
|
+
config: {},
|
|
48
|
+
colors: {}, // Object of pairs of color-name => color hex.
|
|
49
|
+
preferredTheme: null, // The user OS preferred theme (light or dark).
|
|
50
|
+
theme: null, // The current theme (light or dark).
|
|
51
|
+
_notificationManager: null,
|
|
52
|
+
|
|
53
|
+
// Callable from this.$waveui.
|
|
54
|
+
notify (...args) {
|
|
55
|
+
this._notificationManager.notify(...args)
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Callable from this.$waveui.
|
|
59
|
+
switchTheme (theme) {
|
|
60
|
+
this.theme = theme
|
|
61
|
+
document.documentElement.setAttribute('data-theme', theme)
|
|
62
|
+
document.head.querySelector('#wave-ui-colors')?.remove?.()
|
|
63
|
+
const themeColors = this.config.colors[this.theme]
|
|
64
|
+
injectColorsCSSInDOM(themeColors)
|
|
65
|
+
this.colors = flattenColors(themeColors, colorPalette)
|
|
66
|
+
}
|
|
32
67
|
}
|
|
33
68
|
|
|
34
|
-
// A public object containing pairs of color-name => color hex.
|
|
35
|
-
// Accessible from anywhere via `this.$waveui.colors`.
|
|
36
|
-
// These colors generate the CSS in `w-app` on mounted.
|
|
37
|
-
colors = colors.reduce((obj, color) => {
|
|
38
|
-
obj[color.label] = color.color
|
|
39
|
-
color.shades.forEach(shade => (obj[shade.label] = shade.color))
|
|
40
|
-
return obj
|
|
41
|
-
}, { ...config.colors, black: '#000', white: '#fff', transparent: 'transparent', inherit: 'inherit' })
|
|
42
|
-
|
|
43
|
-
config = {} // Store and expose the config in the $waveui object.
|
|
44
|
-
|
|
45
69
|
static install (app, options = {}) {
|
|
46
70
|
// Register directives.
|
|
47
|
-
// for (const id in directives) {
|
|
48
|
-
// if (directives[id]) app.directive(id, directives[id])
|
|
49
|
-
// }
|
|
50
71
|
app.directive('focus', {
|
|
51
72
|
// Wait for the next tick to focus the newly mounted element.
|
|
52
73
|
mounted: el => setTimeout(() => el.focus(), 0)
|
|
@@ -62,71 +83,77 @@ export default class WaveUI {
|
|
|
62
83
|
|
|
63
84
|
// Register a-la-carte components from the given list.
|
|
64
85
|
const { components = {} } = options || {}
|
|
65
|
-
for (
|
|
86
|
+
for (const id in components) {
|
|
66
87
|
const component = components[id]
|
|
88
|
+
// If presets are defined for this component inject them into the props defaults.
|
|
89
|
+
if (options.presets?.[component.name]) injectPresets(component, options.presets[component.name])
|
|
67
90
|
app.component(component.name, component)
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
// Register mixins.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
94
|
+
app.mixin({
|
|
95
|
+
// Add a mixin to capture the first mounted hook, trigger the Wave UI init then unregister the mixin straight away.
|
|
96
|
+
beforeMount () {
|
|
97
|
+
if (!mounted) {
|
|
98
|
+
mounted = true
|
|
99
|
+
const $waveui = inject('$waveui')
|
|
100
|
+
const { config } = $waveui
|
|
101
|
+
|
|
102
|
+
// Add the .w-app class where defined by user or at the root.
|
|
103
|
+
const wApp = document.querySelector(config.on) || document.body
|
|
104
|
+
wApp.classList.add('w-app')
|
|
105
|
+
|
|
106
|
+
let themeColors = config.colors[config.theme]
|
|
107
|
+
if (config.theme === 'auto') {
|
|
108
|
+
detectOSDarkMode($waveui)
|
|
109
|
+
themeColors = config.colors[$waveui.preferredTheme]
|
|
110
|
+
$waveui.colors = flattenColors(themeColors, colorPalette)
|
|
111
|
+
}
|
|
112
|
+
injectColorsCSSInDOM(themeColors)
|
|
113
|
+
injectCSSInDOM($waveui)
|
|
114
|
+
injectNotifManagerInDOM(wApp, components, $waveui)
|
|
115
|
+
|
|
116
|
+
// This mixin must only run once, we can delete it.
|
|
117
|
+
app._context.mixins.find(mixin => mixin.mounted && delete mixin.mounted)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})
|
|
75
121
|
|
|
76
|
-
WaveUI
|
|
122
|
+
new WaveUI(app, options)
|
|
123
|
+
WaveUI.#registered = true
|
|
77
124
|
}
|
|
78
125
|
|
|
79
|
-
// Singleton.
|
|
80
126
|
constructor (app, options = {}) {
|
|
81
|
-
if (WaveUI
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
notificationManager = reactive(new NotificationManager())
|
|
86
|
-
|
|
87
|
-
// Merge user options into the default config.
|
|
88
|
-
mergeConfig(options)
|
|
89
|
-
|
|
90
|
-
// Add color shades for each custom color given in options.
|
|
91
|
-
if (config.css.colorShades) {
|
|
92
|
-
config.colorShades = {}
|
|
127
|
+
if (WaveUI.#registered) {
|
|
128
|
+
console.warn('Wave UI is already instantiated.')
|
|
129
|
+
return
|
|
130
|
+
}
|
|
93
131
|
|
|
94
|
-
|
|
95
|
-
color = { label: color, color: config.colors[color].replace('#', '') }
|
|
96
|
-
const col = color.color
|
|
97
|
-
if (col.length === 3) color.color = col[0] + '' + col[0] + col[1] + col[1] + col[2] + col[2]
|
|
132
|
+
this.$waveui._notificationManager = new NotificationManager()
|
|
98
133
|
|
|
99
|
-
|
|
134
|
+
if (!options.theme) options.theme = 'light'
|
|
135
|
+
// Move colors inside a theme if there are option.colors without theme.
|
|
136
|
+
// E.g. colors: { primary, ... } & not colors: { light { primary, ... }, dark: { primary, ... } })
|
|
137
|
+
const colors = { ...options.colors }
|
|
138
|
+
if (!options.colors?.light) options.colors.light = colors
|
|
139
|
+
if (!options.colors?.dark) options.colors.dark = colors
|
|
140
|
+
// Cleanup anything else than themes in config.colors.
|
|
141
|
+
options.colors = { light: options.colors.light, dark: options.colors.dark }
|
|
100
142
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.colors[`${color.label}-light${i}`] = lighterColor
|
|
105
|
-
this.colors[`${color.label}-dark${i}`] = darkerColor
|
|
143
|
+
// Merge user options into the default config.
|
|
144
|
+
let { components, ...config } = options
|
|
145
|
+
config = this.$waveui.config = mergeConfig(config)
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
config.colorShades[`${color.label}-dark${i}`] = darkerColor
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
147
|
+
// Generates color shades for each color of each theme and store in the config.colors object.
|
|
148
|
+
if (config.css.colorShades) generateColorShades(config)
|
|
113
149
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
150
|
+
// Make Wave UI reactive and expose the single instance in the app.
|
|
151
|
+
const $waveui = reactive(this.$waveui)
|
|
152
|
+
app.config.globalProperties.$waveui = $waveui
|
|
153
|
+
app.provide('$waveui', $waveui)
|
|
117
154
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
app.provide('$waveui', WaveUI.instance)
|
|
155
|
+
if (config.theme !== 'auto') {
|
|
156
|
+
this.$waveui.colors = flattenColors(config.colors[config.theme], colorPalette)
|
|
121
157
|
}
|
|
122
158
|
}
|
|
123
|
-
|
|
124
|
-
notify (...args) {
|
|
125
|
-
notificationManager.notify(...args)
|
|
126
|
-
}
|
|
127
159
|
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Returns the WaveUI instance. Equivalent to using `$waveui` inside templates.
|
|
131
|
-
*/
|
|
132
|
-
export const useWaveUI = () => inject('$waveui')
|
|
@@ -1,10 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
|
|
3
|
+
// The CSS variables are used in the dynamic-css.js file in order to reuse the same SCSS
|
|
4
|
+
// variable presets.
|
|
5
|
+
:root {
|
|
6
|
+
--w-base-increment: #{$base-increment};
|
|
7
|
+
--w-css-scope: #{$css-scope};
|
|
8
|
+
|
|
9
|
+
background-color: rgb(var(--w-base-bg-color-rgb));
|
|
10
|
+
color: rgb(var(--w-base-color-rgb));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
:root[data-theme="light"] {
|
|
14
|
+
--w-base-bg-color-rgb: #{map.get($theme-light, 'base-bg-color-rgb')};
|
|
15
|
+
--w-base-color-rgb: #{map.get($theme-light, 'base-color-rgb')};
|
|
16
|
+
--w-contrast-bg-color-rgb: #{map.get($theme-light, 'contrast-bg-color-rgb')};
|
|
17
|
+
--w-contrast-color-rgb: #{map.get($theme-light, 'contrast-color-rgb')};
|
|
18
|
+
--w-disabled-color-rgb: #{map.get($theme-light, 'disabled-color-rgb')};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:root[data-theme="dark"] {
|
|
22
|
+
--w-base-bg-color-rgb: #{map.get($theme-dark, 'base-bg-color-rgb')};
|
|
23
|
+
--w-base-color-rgb: #{map.get($theme-dark, 'base-color-rgb')};
|
|
24
|
+
--w-contrast-bg-color-rgb: #{map.get($theme-dark, 'contrast-bg-color-rgb')};
|
|
25
|
+
--w-contrast-color-rgb: #{map.get($theme-dark, 'contrast-color-rgb')};
|
|
26
|
+
--w-disabled-color-rgb: #{map.get($theme-dark, 'disabled-color-rgb')};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
* {
|
|
30
|
+
outline: none;
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
}
|
|
2
34
|
|
|
3
35
|
body {overflow-x: hidden;}
|
|
4
36
|
|
|
5
37
|
a {text-decoration: none;}
|
|
6
38
|
|
|
7
|
-
.w-app
|
|
39
|
+
.w-app {
|
|
40
|
+
position: relative; // Make the .w-app a referential for tooltips / menus.
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
min-height: 100vh;
|
|
44
|
+
|
|
45
|
+
&, *, :before, :after {box-sizing: border-box;}
|
|
46
|
+
|
|
47
|
+
&.row {flex-direction: row;}
|
|
48
|
+
&.d-block {display: block;}
|
|
49
|
+
&.align-center {align-items: center;}
|
|
50
|
+
&.align-end {align-items: flex-end;}
|
|
51
|
+
&.justify-center {justify-content: center;}
|
|
52
|
+
&.justify-end {justify-content: flex-end;}
|
|
53
|
+
&.justify-space-between {justify-content: space-between;}
|
|
54
|
+
&.justify-space-around {justify-content: space-around;}
|
|
55
|
+
&.justify-space-evenly {justify-content: space-evenly;}
|
|
56
|
+
&.text-center {text-align: center;}
|
|
57
|
+
&.text-right {text-align: right;}
|
|
58
|
+
}
|
|
8
59
|
|
|
9
60
|
.w-main {
|
|
10
61
|
padding-left: 3 * $base-increment;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
#{$css-scope} {
|
|
2
|
-
.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
.primary-dark3--bg {color: #fff;}
|
|
6
|
-
.white--bg {background-color: #fff;}
|
|
7
|
-
.white {color: #fff;}
|
|
8
|
-
.grey--bg {background-color: #888;}
|
|
9
|
-
.grey {color: #888;}
|
|
10
|
-
.black--bg {background-color: #000;}
|
|
11
|
-
.black {color: #000;}
|
|
12
|
-
.transparent--bg {background-color: transparent;}
|
|
13
|
-
.transparent {color: transparent;}
|
|
14
|
-
.inherit--bg {background-color: inherit;}
|
|
15
|
-
.inherit {color: inherit;}
|
|
16
|
-
.success--bg, .error--bg, .warning--bg, .info--bg {color: #fff;}
|
|
17
|
-
|
|
18
|
-
$colors:(
|
|
2
|
+
// Color palette (immutable).
|
|
3
|
+
// ------------------------------------------------------
|
|
4
|
+
$colors: (
|
|
19
5
|
'pink': #e91e63,
|
|
20
6
|
'purple': #a741b9,
|
|
21
7
|
'deep-purple': #673ab7,
|
|
@@ -37,6 +23,8 @@
|
|
|
37
23
|
'grey': #848484
|
|
38
24
|
);
|
|
39
25
|
|
|
26
|
+
// For each color, create a [color] and a [color]--bg associated classes,
|
|
27
|
+
// + 6 shades lighter and 6 shades darker.
|
|
40
28
|
@each $label, $color in $colors {
|
|
41
29
|
.#{$label}--bg {background-color: $color;}
|
|
42
30
|
.#{$label} {color: $color;}
|
|
@@ -116,4 +104,40 @@
|
|
|
116
104
|
.#{$label}-dark#{$i} {color: darken($color, $dark-increment * $i);}
|
|
117
105
|
}
|
|
118
106
|
}
|
|
107
|
+
|
|
108
|
+
.primary--bg {color: rgb(var(--w-base-bg-color-rgb));}
|
|
109
|
+
.white--bg {background-color: #fff;}
|
|
110
|
+
.white {color: #fff;}
|
|
111
|
+
.black--bg {background-color: #000;}
|
|
112
|
+
.black {color: #000;}
|
|
113
|
+
.transparent--bg {background-color: transparent;}
|
|
114
|
+
.transparent {color: transparent;}
|
|
115
|
+
.inherit--bg {background-color: inherit;}
|
|
116
|
+
.inherit {color: inherit;}
|
|
117
|
+
// ------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
// Theming colors.
|
|
120
|
+
// These classes carry colors which change automatically when switching theme.
|
|
121
|
+
// ------------------------------------------------------
|
|
122
|
+
.base-color {color: rgba(var(--w-base-color-rgb), 0.7);}
|
|
123
|
+
.base-color--bg {background-color: rgb(var(--w-base-bg-color-rgb));}
|
|
124
|
+
.contrast-color {color: rgba(var(--w-contrast-color-rgb), 0.7);}
|
|
125
|
+
.contrast-color--bg {background-color: rgb(var(--w-contrast-bg-color-rgb));}
|
|
126
|
+
// ------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
// Status colors - must stay last and have highest priority.
|
|
129
|
+
// ------------------------------------------------------
|
|
130
|
+
.info {color: var(--w-info-color);}
|
|
131
|
+
.info--bg {background-color: var(--w-info-color);color: #fff;}
|
|
132
|
+
.warning {color: var(--w-warning-color);}
|
|
133
|
+
.warning--bg {background-color: var(--w-warning-color);color: #fff;}
|
|
134
|
+
.success {color: var(--w-success-color);}
|
|
135
|
+
.success--bg {background-color: var(--w-success-color);color: #fff;}
|
|
136
|
+
.error {color: var(--w-error-color);}
|
|
137
|
+
.error--bg {background-color: var(--w-error-color);color: #fff;}
|
|
138
|
+
// ------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
// The only colors remaining to define are user custom colors and shades.
|
|
141
|
+
// The associated CSS will be generated from dynamic-css.js, and injected as a first stylesheet,
|
|
142
|
+
// before this one (so the rules in this file have more priority).
|
|
119
143
|
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
// The CSS variables are used in the dynamic-css.js file in order to reuse the same SCSS
|
|
2
|
-
// variable presets.
|
|
3
|
-
:root {
|
|
4
|
-
--base-increment: #{$base-increment};
|
|
5
|
-
--css-scope: #{$css-scope};
|
|
6
|
-
}
|
|
7
|
-
|
|
8
1
|
// All these CSS classes will not be generated if the $use-layout-classes is set to false.
|
|
9
2
|
@if $use-layout-classes {
|
|
10
3
|
#{$css-scope} {
|
|
@@ -170,7 +163,7 @@
|
|
|
170
163
|
|
|
171
164
|
// Sizes.
|
|
172
165
|
// ----------------------------------------------
|
|
173
|
-
// In all the sizes
|
|
166
|
+
// In all the sizes below, round(x / 2) * 2 to always have even numbers.
|
|
174
167
|
// Different heights with a mix of odd and even numbers will misalign
|
|
175
168
|
// when vertically centering (vertical-align or align-items center).
|
|
176
169
|
.size--xs {font-size: round(0.85 * $base-font-size);}
|
|
@@ -186,25 +179,25 @@
|
|
|
186
179
|
// (https://www.w3.org/TR/css-variables-1/#using-variables),
|
|
187
180
|
// the grid system is done dynamically in dynamic-css.js.
|
|
188
181
|
|
|
189
|
-
// @media screen and (min-width: var(--breakpoint-xs)) {
|
|
182
|
+
// @media screen and (min-width: var(--w-breakpoint-xs)) {
|
|
190
183
|
// @for $i from 0 through $grid-base {
|
|
191
184
|
// .sm#{$grid-base - $i} {width: ($grid-base - $i) * 100% / $grid-base;}
|
|
192
185
|
// }
|
|
193
186
|
// }
|
|
194
187
|
|
|
195
|
-
// @media screen and (min-width: var(--breakpoint-sm)) {
|
|
188
|
+
// @media screen and (min-width: var(--w-breakpoint-sm)) {
|
|
196
189
|
// @for $i from 0 through $grid-base {
|
|
197
190
|
// .md#{$grid-base - $i} {width: ($grid-base - $i) * 100% / $grid-base;}
|
|
198
191
|
// }
|
|
199
192
|
// }
|
|
200
193
|
|
|
201
|
-
// @media screen and (min-width: var(--breakpoint-md)) {
|
|
194
|
+
// @media screen and (min-width: var(--w-breakpoint-md)) {
|
|
202
195
|
// @for $i from 0 through $grid-base {
|
|
203
196
|
// .lg#{$grid-base - $i} {width: ($grid-base - $i) * 100% / $grid-base;}
|
|
204
197
|
// }
|
|
205
198
|
// }
|
|
206
199
|
|
|
207
|
-
// @media screen and (min-width: var(--breakpoint-lg)) {
|
|
200
|
+
// @media screen and (min-width: var(--w-breakpoint-lg)) {
|
|
208
201
|
// @for $i from 0 through $grid-base {
|
|
209
202
|
// .xl#{$grid-base - $i} {width: ($grid-base - $i) * 100% / $grid-base;}
|
|
210
203
|
// }
|
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
|
|
3
|
+
// This allows each UI component to be used in dark or light theme regardless of the global theme.
|
|
4
|
+
@mixin themeable {
|
|
5
|
+
// Will force the light style on this component.
|
|
6
|
+
&--light {
|
|
7
|
+
--w-base-bg-color-rgb: #{map.get($theme-light, 'base-bg-color-rgb')};
|
|
8
|
+
--w-base-color-rgb: #{map.get($theme-light, 'base-color-rgb')};
|
|
9
|
+
--w-contrast-bg-color-rgb: #{map.get($theme-light, 'contrast-bg-color-rgb')};
|
|
10
|
+
--w-contrast-color-rgb: #{map.get($theme-light, 'contrast-color-rgb')};
|
|
11
|
+
--w-disabled-color-rgb: #{map.get($theme-light, 'disabled-color-rgb')};
|
|
12
|
+
color: rgba(var(--w-base-color-rgb), 0.7);
|
|
13
|
+
}
|
|
14
|
+
// Will force the dark style on this component.
|
|
15
|
+
&--dark {
|
|
16
|
+
--w-base-bg-color-rgb: #{map.get($theme-dark, 'base-bg-color-rgb')};
|
|
17
|
+
--w-base-color-rgb: #{map.get($theme-dark, 'base-color-rgb')};
|
|
18
|
+
--w-contrast-bg-color-rgb: #{map.get($theme-dark, 'contrast-bg-color-rgb')};
|
|
19
|
+
--w-contrast-color-rgb: #{map.get($theme-dark, 'contrast-color-rgb')};
|
|
20
|
+
--w-disabled-color-rgb: #{map.get($theme-dark, 'disabled-color-rgb')};
|
|
21
|
+
color: rgba(var(--w-base-color-rgb), 0.7);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
1
25
|
@mixin default-transition($duration: $transition-duration, $delay: 0s) {
|
|
2
26
|
transition: $duration $delay ease-in-out;
|
|
3
27
|
}
|