wave-ui 2.48.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.
Files changed (48) hide show
  1. package/dist/wave-ui.cjs.js +1 -1
  2. package/dist/wave-ui.css +1 -1
  3. package/dist/wave-ui.es.js +1630 -1419
  4. package/dist/wave-ui.umd.js +1 -1
  5. package/package.json +4 -3
  6. package/src/wave-ui/components/index.js +1 -0
  7. package/src/wave-ui/components/w-accordion.vue +8 -2
  8. package/src/wave-ui/components/w-alert.vue +10 -4
  9. package/src/wave-ui/components/w-app.vue +2 -107
  10. package/src/wave-ui/components/w-badge.vue +7 -3
  11. package/src/wave-ui/components/w-button/button.vue +6 -2
  12. package/src/wave-ui/components/w-card.vue +14 -4
  13. package/src/wave-ui/components/w-checkbox.vue +15 -8
  14. package/src/wave-ui/components/w-confirm.vue +5 -1
  15. package/src/wave-ui/components/w-date-picker.vue +6 -0
  16. package/src/wave-ui/components/w-dialog.vue +9 -3
  17. package/src/wave-ui/components/w-divider.vue +9 -3
  18. package/src/wave-ui/components/w-drawer.vue +9 -3
  19. package/src/wave-ui/components/w-input.vue +4 -2
  20. package/src/wave-ui/components/w-menu.vue +11 -4
  21. package/src/wave-ui/components/w-notification-manager.vue +18 -30
  22. package/src/wave-ui/components/w-notification.vue +7 -1
  23. package/src/wave-ui/components/w-progress.vue +2 -2
  24. package/src/wave-ui/components/w-radio.vue +8 -2
  25. package/src/wave-ui/components/w-rating.vue +11 -3
  26. package/src/wave-ui/components/w-scrollbar.vue +24 -0
  27. package/src/wave-ui/components/w-select.vue +9 -5
  28. package/src/wave-ui/components/w-slider.vue +13 -7
  29. package/src/wave-ui/components/w-steps.vue +14 -4
  30. package/src/wave-ui/components/w-switch.vue +14 -14
  31. package/src/wave-ui/components/w-table.vue +25 -11
  32. package/src/wave-ui/components/w-tabs/index.vue +8 -2
  33. package/src/wave-ui/components/w-tag.vue +15 -10
  34. package/src/wave-ui/components/w-textarea.vue +6 -2
  35. package/src/wave-ui/components/w-timeline.vue +18 -5
  36. package/src/wave-ui/components/w-toolbar.vue +8 -2
  37. package/src/wave-ui/components/w-tooltip.vue +10 -4
  38. package/src/wave-ui/components/w-tree.vue +47 -15
  39. package/src/wave-ui/core.js +117 -90
  40. package/src/wave-ui/scss/_base.scss +53 -2
  41. package/src/wave-ui/scss/_colors.scss +41 -17
  42. package/src/wave-ui/scss/_layout.scss +5 -12
  43. package/src/wave-ui/scss/_mixins.scss +24 -0
  44. package/src/wave-ui/scss/_variables.scss +100 -11
  45. package/src/wave-ui/utils/colors.js +60 -3
  46. package/src/wave-ui/utils/config.js +35 -11
  47. package/src/wave-ui/utils/dynamic-css.js +92 -30
  48. package/src/wave-ui/utils/notification-manager.js +39 -8
@@ -5,43 +5,49 @@ const cssVars = {
5
5
  baseIncrement: 4
6
6
  }
7
7
 
8
- const generateColors = config => {
8
+ // Global var for faster results in the resize event handler.
9
+ let breakpointsDef = { keys: [], values: [] }
10
+ let currentBreakpoint = null
11
+
12
+ // Generates the CSS for all the dynamic colors and shades. E.g.
13
+ // :root {[color1-variable], [color2-variable]}
14
+ // .color1--bg {background-color: [color1-variable]}
15
+ // .color1 {color: [color1-variable]}
16
+ const generateColors = themeColors => {
9
17
  let styles = ''
10
- const { cssScope } = cssVars
18
+ const cssVariables = {}
11
19
 
12
20
  // Extract status colors and place them after the other colors.
13
- const { info, warning, success, error, ...colors } = config.colors
21
+ const { info, warning, success, error, shades, ...colors } = themeColors
22
+ const { cssScope } = cssVars
14
23
 
15
- for (const color in colors) {
24
+ // User custom colors.
25
+ // ------------------------------------------------------
26
+ for (const colorName in colors) {
16
27
  styles +=
17
- `${cssScope} .${color}--bg{background-color:${config.colors[color]}}` +
18
- `${cssScope} .${color}{color:${config.colors[color]}}`
28
+ `${cssScope} .${colorName}--bg{background-color:var(--w-${colorName}-color)}` +
29
+ `${cssScope} .${colorName}{color:var(--w-${colorName}-color)}`
19
30
  }
20
-
21
- // Color shades are generated in core.js, if the option is on.
22
- if (config.css.colorShades && config.colorShades) {
23
- Object.entries(config.colorShades).forEach(([label, color]) => {
24
- styles +=
25
- `${cssScope} .${label}--bg{background-color:${color}}` +
26
- `${cssScope} .${label}{color:${color}}`
27
- })
31
+ // The shades don't need css vars.
32
+ for (const colorName in shades) {
33
+ styles +=
34
+ `${cssScope} .${colorName}--bg{background-color:${shades[colorName]}}` +
35
+ `${cssScope} .${colorName}{color:${shades[colorName]}}`
28
36
  }
29
37
 
38
+ // Creating CSS3 variables.
39
+ // ------------------------------------------------------
40
+ // Create a CSS variable for each color for theming and reuse in components.
30
41
  // Status colors must remain after the other colors so they have priority in form validations.
31
42
  // That only makes sense when there are 2 colors on the same element: e.g. `span.primary.error`.
32
- const statusColors = { info, warning, success, error } // This order is also important for priorities.
33
- for (const color in statusColors) {
34
- styles +=
35
- `${cssScope} .${color}--bg{background-color:${config.colors[color]}}` +
36
- `${cssScope} .${color}{color:${config.colors[color]}}`
37
- }
38
-
39
- // Add the primary color to the CSS variables for reuse in components.
40
- const cssVariables = []
41
- cssVariables.push(`--primary: ${config.colors.primary}`)
42
- styles += `:root {${cssVariables.join(';')}}`
43
+ const allColors = { ...colors, info, warning, success, error }
44
+ for (const colorName in allColors) cssVariables[colorName] = allColors[colorName]
45
+ let cssVariablesString = ''
46
+ Object.entries(cssVariables).forEach(([colorName, colorHex]) => {
47
+ cssVariablesString += `--w-${colorName}-color: ${colorHex};`
48
+ })
43
49
 
44
- return styles
50
+ return `:root{${cssVariablesString}}${styles}`
45
51
  }
46
52
 
47
53
  // Generate the layout grid. E.g. xs1, xs2, ..., xl12.
@@ -218,7 +224,64 @@ const genBreakpointLayoutClasses = breakpoints => {
218
224
  return styles
219
225
  }
220
226
 
221
- export default config => {
227
+ const getBreakpoint = $waveui => {
228
+ const width = window.innerWidth
229
+ const breakpoints = breakpointsDef.values.slice(0)
230
+ // Most performant lookup.
231
+ breakpoints.push(width)
232
+ breakpoints.sort((a, b) => a - b)
233
+ const breakpoint = breakpointsDef.keys[breakpoints.indexOf(width)] || 'xl'
234
+
235
+ if (breakpoint !== currentBreakpoint) {
236
+ currentBreakpoint = breakpoint
237
+ $waveui.breakpoint = {
238
+ name: breakpoint,
239
+ xs: breakpoint === 'xs',
240
+ sm: breakpoint === 'sm',
241
+ md: breakpoint === 'md',
242
+ lg: breakpoint === 'lg',
243
+ xl: breakpoint === 'xl',
244
+ width
245
+ }
246
+ }
247
+
248
+ $waveui.breakpoint.width = window.innerWidth
249
+ }
250
+
251
+ // Should run on first mounted hook.
252
+ export const injectCSSInDOM = $waveui => {
253
+ const { config } = $waveui
254
+ breakpointsDef = { keys: Object.keys(config.breakpoints), values: Object.values(config.breakpoints) }
255
+
256
+ // Inject global dynamic CSS classes in document head.
257
+ if (!document.getElementById('wave-ui-styles')) {
258
+ const css = document.createElement('style')
259
+ css.id = 'wave-ui-styles'
260
+ css.innerHTML = doDynamicCSS(config)
261
+
262
+ const firstStyle = document.head.querySelectorAll('style,link[rel="stylesheet"]')[0]
263
+ if (firstStyle) firstStyle.before(css)
264
+ else document.head.appendChild(css)
265
+ }
266
+
267
+ getBreakpoint($waveui)
268
+ window.addEventListener('resize', () => getBreakpoint($waveui))
269
+ }
270
+
271
+ export const injectColorsCSSInDOM = themeColors => {
272
+ // Inject global dynamic CSS classes in document head.
273
+ if (!document.getElementById('wave-ui-colors')) {
274
+ const css = document.createElement('style')
275
+ css.id = 'wave-ui-colors'
276
+ css.innerHTML = generateColors(themeColors)
277
+
278
+ const firstStyle = document.head.querySelectorAll('style,link[rel="stylesheet"]')[0]
279
+ if (firstStyle) firstStyle.before(css)
280
+ else document.head.appendChild(css)
281
+ }
282
+ }
283
+
284
+ const doDynamicCSS = config => {
222
285
  const entries = Object.entries(config.breakpoints)
223
286
  const breakpointsDef = entries.map(([label, max], i) => {
224
287
  // Construct the breakpoint objects.
@@ -227,11 +290,10 @@ export default config => {
227
290
  })
228
291
 
229
292
  const computedStyles = getComputedStyle(document.documentElement)
230
- cssVars.cssScope = computedStyles.getPropertyValue('--css-scope')
231
- cssVars.baseIncrement = parseInt(computedStyles.getPropertyValue('--base-increment'))
293
+ cssVars.cssScope = computedStyles.getPropertyValue('--w-css-scope')
294
+ cssVars.baseIncrement = parseInt(computedStyles.getPropertyValue('--w-base-increment'))
232
295
 
233
296
  let styles = ''
234
- styles += generateColors(config)
235
297
  styles += generateBreakpoints(breakpointsDef, config.css.grid)
236
298
  if (config.css.breakpointLayoutClasses) styles += genBreakpointLayoutClasses(breakpointsDef)
237
299
  // if (config.css.breakpointSpaces) styles += generateBreakpointSpaces(breakpointsDef)
@@ -1,9 +1,8 @@
1
- // @todo: find a way to use private fields with Vue 3 proxies.
2
- // https://github.com/tc39/proposal-class-fields/issues/106
3
- // https://github.com/tc39/proposal-class-fields/issues/227
1
+ import { createApp, defineComponent } from 'vue'
2
+ import WNotificationManager from '../components/w-notification-manager.vue'
4
3
 
5
- export default class NotificationManager {
6
- static instance
4
+ export class NotificationManager {
5
+ static #instance
7
6
  notifications
8
7
  // Private fields.
9
8
  _uid // A unique ID for each notification.
@@ -11,9 +10,8 @@ export default class NotificationManager {
11
10
 
12
11
  constructor () {
13
12
  // Singleton pattern.
14
- if (NotificationManager.instance) return NotificationManager.instance
13
+ if (NotificationManager.#instance) return NotificationManager.#instance
15
14
 
16
- NotificationManager.instance = this
17
15
  this.notifications = []
18
16
  this._uid = 0
19
17
  this._notificationDefaults = {
@@ -23,10 +21,14 @@ export default class NotificationManager {
23
21
  timeout: 4000,
24
22
  dismiss: true
25
23
  }
24
+ NotificationManager.#instance = this
26
25
  }
27
26
 
28
27
  notify (...args) {
29
- let notification = { ...this._notificationDefaults, _uid: this._uid++ }
28
+ let notification = {
29
+ ...this._notificationDefaults,
30
+ _uid: this._uid++
31
+ }
30
32
 
31
33
  if (typeof args[0] === 'object') notification = { ...notification, ...args[0] }
32
34
  else {
@@ -38,6 +40,10 @@ export default class NotificationManager {
38
40
  timeout: timeout || timeout === 0 ? parseFloat(timeout) : 4000
39
41
  }
40
42
  }
43
+
44
+ // Allow calling notification.dismiss().
45
+ if (notification.dismiss) notification.dismiss = () => this.dismiss(notification._uid)
46
+
41
47
  this.notifications.push(notification)
42
48
  if (~~notification.timeout !== 0) setTimeout(() => this.dismiss(notification._uid), notification.timeout)
43
49
  }
@@ -46,3 +52,28 @@ export default class NotificationManager {
46
52
  this.notifications = this.notifications.filter(item => item._uid !== uid)
47
53
  }
48
54
  }
55
+
56
+ /**
57
+ * Injects the w-notification-manager in the DOM programmatically so the user does not have to do it.
58
+ *
59
+ * @param {Object} wApp The DOM element where to mount the w-notification-manager.
60
+ * @param {Object} components All the Wave UI components to provide to the w-notification-manager,
61
+ * so it can also use them.
62
+ * @param {Object} $waveui the injected reactive instance of the WaveUI class.
63
+ */
64
+ export const injectNotifManagerInDOM = (wApp, components, $waveui) => {
65
+ const div = document.createElement('div')
66
+ wApp.appendChild(div)
67
+
68
+ const WNotifManager = createApp(defineComponent({
69
+ ...WNotificationManager,
70
+ inject: ['$waveui']
71
+ })).provide('$waveui', $waveui)
72
+
73
+ for (const id in components) {
74
+ const component = components[id]
75
+ WNotifManager.component(component.name, { ...component, inject: ['$waveui'] })
76
+ }
77
+ WNotifManager.mount(div)
78
+ div.remove() // The WNotificationManager contains a teleport to .w-app.
79
+ }