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.
Files changed (50) 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 +1920 -1638
  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/transitions/w-transition-expand.vue +26 -15
  8. package/src/wave-ui/components/w-accordion.vue +8 -2
  9. package/src/wave-ui/components/w-alert.vue +10 -4
  10. package/src/wave-ui/components/w-app.vue +2 -107
  11. package/src/wave-ui/components/w-badge.vue +7 -3
  12. package/src/wave-ui/components/w-button/button.vue +6 -2
  13. package/src/wave-ui/components/w-card.vue +14 -4
  14. package/src/wave-ui/components/w-checkbox.vue +15 -8
  15. package/src/wave-ui/components/w-confirm.vue +7 -2
  16. package/src/wave-ui/components/w-date-picker.vue +6 -0
  17. package/src/wave-ui/components/w-dialog.vue +9 -3
  18. package/src/wave-ui/components/w-divider.vue +9 -3
  19. package/src/wave-ui/components/w-drawer.vue +9 -3
  20. package/src/wave-ui/components/w-input.vue +4 -2
  21. package/src/wave-ui/components/w-list.vue +1 -1
  22. package/src/wave-ui/components/w-menu.vue +11 -4
  23. package/src/wave-ui/components/w-notification-manager.vue +18 -30
  24. package/src/wave-ui/components/w-notification.vue +7 -1
  25. package/src/wave-ui/components/w-progress.vue +2 -2
  26. package/src/wave-ui/components/w-radio.vue +8 -2
  27. package/src/wave-ui/components/w-rating.vue +11 -3
  28. package/src/wave-ui/components/w-scrollbar.vue +24 -0
  29. package/src/wave-ui/components/w-select.vue +18 -8
  30. package/src/wave-ui/components/w-slider.vue +13 -7
  31. package/src/wave-ui/components/w-steps.vue +14 -4
  32. package/src/wave-ui/components/w-switch.vue +14 -14
  33. package/src/wave-ui/components/w-table.vue +107 -16
  34. package/src/wave-ui/components/w-tabs/index.vue +8 -2
  35. package/src/wave-ui/components/w-tag.vue +15 -10
  36. package/src/wave-ui/components/w-textarea.vue +6 -2
  37. package/src/wave-ui/components/w-timeline.vue +18 -5
  38. package/src/wave-ui/components/w-toolbar.vue +8 -2
  39. package/src/wave-ui/components/w-tooltip.vue +10 -4
  40. package/src/wave-ui/components/w-tree.vue +57 -19
  41. package/src/wave-ui/core.js +117 -90
  42. package/src/wave-ui/scss/_base.scss +53 -2
  43. package/src/wave-ui/scss/_colors.scss +41 -17
  44. package/src/wave-ui/scss/_layout.scss +5 -12
  45. package/src/wave-ui/scss/_mixins.scss +24 -0
  46. package/src/wave-ui/scss/_variables.scss +100 -11
  47. package/src/wave-ui/utils/colors.js +60 -3
  48. package/src/wave-ui/utils/config.js +35 -11
  49. package/src/wave-ui/utils/dynamic-css.js +92 -30
  50. package/src/wave-ui/utils/notification-manager.js +39 -8
@@ -1,10 +1,40 @@
1
1
  @use "sass:math";
2
+ @use "sass:map";
2
3
 
3
4
  @function divide($a, $b) {
4
5
  @return math.div($a, $b); // Must use `sass` & not `node-sass`.
5
- // @return $a / $b;
6
6
  }
7
7
 
8
+ // THEME COLORS.
9
+ // ========================================================
10
+ // These colors are defined by a list of RBG channels only, so you can later apply any alpha channel.
11
+ // If you don't need themes, you can leave this as is and override the global defaults.
12
+ $theme-light: (
13
+ base-bg-color-rgb: (255, 255, 255), // #fff.
14
+ base-color-rgb: (0, 0, 0), // #000.
15
+ contrast-bg-color-rgb: (0, 0, 0), // #000.
16
+ contrast-color-rgb: (255, 255, 255), // #fff.
17
+ disabled-color-rgb: (204, 204, 204), // #ccc.
18
+ ) !default;
19
+
20
+ $theme-dark: (
21
+ base-bg-color-rgb: (34, 34, 34), // #222.
22
+ base-color-rgb: (255, 255, 255), // #fff.
23
+ contrast-bg-color-rgb: (255, 255, 255), // #fff.
24
+ contrast-color-rgb: (0, 0, 0), // #000.
25
+ disabled-color-rgb: (74, 74, 74), // #4a4a4a.
26
+ ) !default;
27
+
28
+ // These variables are filled up with the current theme colors for you to use.
29
+ $primary: var(--w-primary-color);
30
+ $secondary: var(--w-secondary-color);
31
+ $base-bg-color: rgb(var(--w-base-bg-color-rgb));
32
+ $base-color: rgb(var(--w-base-color-rgb));
33
+ $contrast-bg-color: rgb(var(--w-contrast-bg-color-rgb));
34
+ $contrast-color: rgb(var(--w-contrast-color-rgb));
35
+ // When a form element is disabled (checkbox, radio, input, select list).
36
+ $disabled-color: rgb(var(--w-disabled-color-rgb));
37
+
8
38
  // GLOBAL DEFAULTS.
9
39
  // ========================================================
10
40
  $css-scope: '.w-app' !default; // Allows control on CSS rules priority.
@@ -15,47 +45,106 @@ $base-font-size: 14px !default; // Must be a px unit.
15
45
  $base-increment: round(divide($base-font-size, 4)) !default;
16
46
  $layout-padding: $base-increment * 4 !default; // Applied on the .content-wrap tag.
17
47
  $border-radius: 3px !default;
18
- $border-color: rgba(0, 0, 0, 0.15);
48
+ $border-color: rgba(var(--w-contrast-bg-color-rgb), 0.15) !default;
19
49
  $border: 1px solid $border-color !default;
20
50
  $transition-duration: 0.25s !default;
21
51
  $fast-transition-duration: 0.15s !default;
22
52
  $box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
23
53
  0 2px 2px 0 rgba(0, 0, 0, 0.15),
24
54
  0 1px 5px 0 rgba(0, 0, 0, 0.15) !default;
25
- // When a form element is disabled (checkbox, radio, input, select list).
26
- $disabled-color: #ccc;
27
55
  $form-field-height: round(2 * $base-font-size) !default;
28
56
  // Always an even number for better vertical alignment. (Used in checkbox, radio, switch)
29
57
  $small-form-el-size: round(divide(1.3 * $base-font-size, 2)) * 2 !default;
30
58
 
59
+ // Detachable elements are: w-tooltip, w-menu, w-confirm.
60
+ $detachable-bg-color: $base-bg-color !default;
61
+ $detachable-color: $base-color !default;
62
+
31
63
  // COMPONENTS DEFAULTS.
32
64
  // ========================================================
65
+ // w-confirm.
66
+ // --------------------------------------------------------
67
+ $confirm-bg-color: $detachable-bg-color !default;
68
+ $confirm-color: $detachable-color !default;
69
+ // --------------------------------------------------------
70
+
71
+ // w-dialog.
72
+ // --------------------------------------------------------
73
+ $dialog-bg-color: $base-bg-color !default;
74
+ // --------------------------------------------------------
75
+
76
+ // w-divider.
77
+ // --------------------------------------------------------
78
+ $divider-color: $border-color !default;
79
+ // --------------------------------------------------------
80
+
33
81
  // w-drawer.
82
+ // --------------------------------------------------------
34
83
  $drawer-max-size: 380px !default;
84
+ $drawer-bg-color: $base-bg-color !default;
85
+ // --------------------------------------------------------
86
+
87
+ // w-menu.
88
+ // --------------------------------------------------------
89
+ $menu-bg-color: $detachable-bg-color !default;
90
+ $menu-color: $detachable-color !default;
91
+ // --------------------------------------------------------
92
+
93
+ // w-progress.
94
+ // --------------------------------------------------------
95
+ $progress-bg-color: rgba(var(--w-contrast-bg-color-rgb), 0.15) !default;
96
+ // --------------------------------------------------------
97
+
98
+ // w-rating.
99
+ // --------------------------------------------------------
100
+ $rating-bg-color: rgba(var(--w-contrast-bg-color-rgb), 0.25) !default;
35
101
  // --------------------------------------------------------
36
102
 
37
103
  // w-slider.
38
104
  // --------------------------------------------------------
39
105
  $slider-height: $base-increment !default;
40
- $slider-track-color: #ddd;
106
+ $slider-track-color: rgba(var(--w-contrast-bg-color-rgb), 0.15) !default;
107
+ $slider-thumb-button-bg-color: $base-bg-color !default;
108
+ $slider-thumb-label-bg-color: $base-bg-color !default;
109
+ $slider-thumb-label-color: rgba(var(--w-base-color-rgb), 0.75) !default;
110
+ $slider-step-label-bg-color: rgba(var(--w-contrast-bg-color-rgb), 0.2) !default;
111
+ $slider-step-label-color: rgba(var(--w-base-color-rgb), 0.5) !default;
112
+
113
+ // w-switch.
114
+ // --------------------------------------------------------
115
+ $switch-inactive-color: rgba(var(--w-contrast-bg-color-rgb), 0.25) !default;
116
+ $switch-thumb-color: #fff !default;
41
117
  // --------------------------------------------------------
42
118
 
43
119
  // w-table.
44
120
  // --------------------------------------------------------
45
- $table-tr-odd-color: rgba(0, 0, 0, 0.02);
46
- $table-tr-hover-color: rgba(0, 0, 0, 0.05);
47
- $table-color: rgba(0, 0, 0, 0.7);
121
+ $table-tr-odd-color: rgba(0, 0, 0, 0.02) !default;
122
+ $table-tr-hover-color: rgba(0, 0, 0, 0.05) !default;
123
+ $table-color: rgba(var(--w-contrast-color-rgb), 0.7) !default;
48
124
  // --------------------------------------------------------
49
125
 
50
126
  // w-textarea.
51
127
  // --------------------------------------------------------
52
- $textarea-line-height: 1.2;
128
+ $textarea-line-height: 1.2 !default;
129
+ // --------------------------------------------------------
130
+
131
+ // w-timeline.
132
+ // --------------------------------------------------------
133
+ $timeline-bullet-color: $base-bg-color !default;
134
+ $timeline-bg-color: rgba(var(--w-contrast-bg-color-rgb), 0.25) !default;
135
+ // --------------------------------------------------------
136
+
137
+ // w-toolbar.
138
+ // --------------------------------------------------------
139
+ $toolbar-max-size: 380px !default;
140
+ $toolbar-bg-color: $base-bg-color !default;
53
141
  // --------------------------------------------------------
54
142
 
55
143
  // w-tooltip.
56
144
  // --------------------------------------------------------
57
- $tooltip-bg-color: #fff;
58
- $tooltip-color: rgba(0, 0, 0, 0.7);
145
+ $tooltip-bg-color: $detachable-bg-color !default;
146
+ $tooltip-color: $detachable-color !default;
147
+ $tooltip-border-color: $border-color !default;
59
148
  // --------------------------------------------------------
60
149
 
61
150
  // Mixins.
@@ -1,4 +1,58 @@
1
- export default [
1
+ const shadeColor = (color, amount) => {
2
+ return '#' + color.slice(1).match(/../g)
3
+ .map(x => {
4
+ x = +`0x${x}` + amount
5
+ return (x < 0 ? 0 : (x > 255 ? 255 : x)).toString(16).padStart(2, 0)
6
+ })
7
+ .join('')
8
+ }
9
+
10
+ /**
11
+ * Generates the color shades for each custom color and status colors for the current theme (only),
12
+ * and save it in the config object.
13
+ *
14
+ * @param {Object} config
15
+ */
16
+ export const generateColorShades = config => {
17
+ // Add color shades for each custom color and status color of each theme.
18
+ ['light', 'dark'].forEach(theme => {
19
+ const themeOfColors = config.colors[theme]
20
+ themeOfColors.shades = {}
21
+
22
+ for (let color in themeOfColors) {
23
+ if (color === 'shades') continue // Skip if item is the `shades` container.
24
+ color = { label: color, color: themeOfColors[color].replace('#', '') }
25
+ const col = color.color
26
+ if (col.length === 3) color.color = col[0] + '' + col[0] + col[1] + col[1] + col[2] + col[2]
27
+
28
+ for (let i = 1; i <= 3; i++) {
29
+ const lighterColor = shadeColor(`#${color.color}`, i * 40)
30
+ const darkerColor = shadeColor(`#${color.color}`, -i * 40)
31
+ // Adding the shades to the config object to generate the CSS from w-app.
32
+ themeOfColors.shades[`${color.label}-light${i}`] = lighterColor
33
+ themeOfColors.shades[`${color.label}-dark${i}`] = darkerColor
34
+ }
35
+ }
36
+ })
37
+ }
38
+
39
+ export const flattenColors = (themeColors, colorPalette) => {
40
+ const colors = {
41
+ ...colorPalette.reduce((obj, color) => {
42
+ obj[color.label] = color.color
43
+ const shades = (color.shades || []).reduce((obj, color) => {
44
+ obj[color.label] = color.color
45
+ return obj
46
+ }, {})
47
+ return { ...obj, ...shades }
48
+ }, { ...themeColors, ...themeColors.shades })
49
+ }
50
+ delete colors.shades
51
+
52
+ return colors
53
+ }
54
+
55
+ export const colorPalette = [
2
56
  {
3
57
  label: 'pink',
4
58
  color: '#e91e63',
@@ -15,7 +69,6 @@ export default [
15
69
  { label: 'pink-dark4', color: '#7c0c32' },
16
70
  { label: 'pink-dark5', color: '#600927' },
17
71
  { label: 'pink-dark6', color: '#43071b' }
18
-
19
72
  ]
20
73
  },
21
74
  {
@@ -342,5 +395,9 @@ export default [
342
395
  { label: 'grey-dark5', color: '#353535' },
343
396
  { label: 'grey-dark6', color: '#252525' }
344
397
  ]
345
- }
398
+ },
399
+ { label: 'black', color: '#000' },
400
+ { label: 'white', color: '#fff' },
401
+ { label: 'transparent', color: 'transparent' },
402
+ { label: 'inherit', color: 'inherit' }
346
403
  ]
@@ -1,6 +1,7 @@
1
1
  import { reactive } from 'vue'
2
2
 
3
3
  const config = reactive({
4
+ on: '#app', // Sets the Wave UI root node. If not found, will default to `body`.
4
5
  breakpoints: {
5
6
  xs: 600,
6
7
  sm: 900,
@@ -10,7 +11,7 @@ const config = reactive({
10
11
  },
11
12
  css: {
12
13
  // Generate shades for custom colors and status colors.
13
- // Palette color shades are always generated with palette.
14
+ // Note: the color palette shades are always generated separately from SCSS.
14
15
  colorShades: true,
15
16
 
16
17
  // Generate palette colors and palette color shades.
@@ -24,13 +25,27 @@ const config = reactive({
24
25
  grid: 12
25
26
  },
26
27
  colors: {
27
- primary: '#234781',
28
- secondary: '#d3ebff',
29
- success: '#54b946',
30
- error: '#f65555',
31
- warning: '#f80',
32
- info: '#3d9ff5'
28
+ // Default colors of Wave UI. Can be overridden from the Wave UI user config on init.
29
+ light: {
30
+ primary: '#234781',
31
+ secondary: '#d3ebff',
32
+ info: '#3d9ff5',
33
+ warning: '#f80',
34
+ success: '#54b946',
35
+ error: '#f65555'
36
+ },
37
+ dark: {
38
+ primary: '#89b6d2',
39
+ secondary: '#375b6a',
40
+ info: '#3d9ff5',
41
+ warning: '#f80',
42
+ success: '#54b946',
43
+ error: '#f65555'
44
+ }
33
45
  },
46
+ // The initial theme to use.
47
+ // To switch theme while running, call the $waveui.switchTheme('light'|'dark') method.
48
+ theme: 'light', // One of 'light', 'dark', 'auto'.
34
49
  icons: [],
35
50
  iconsLigature: false,
36
51
  notificationManager: {
@@ -43,9 +58,18 @@ const config = reactive({
43
58
  export { config as default }
44
59
 
45
60
  export const mergeConfig = (options, conf = config) => {
46
- for (const key in options) {
47
- const option = options[key]
48
- if (typeof option === 'object') mergeConfig(options[key], conf[key])
49
- else conf[key] = option
61
+ // If the conf object is empty, populate with options (case of presets).
62
+ if (!Object.keys(conf).length) conf = Object.assign(conf, options)
63
+
64
+ else {
65
+ for (const key in options) {
66
+ const option = options[key]
67
+ if (typeof option === 'object') {
68
+ mergeConfig(options[key], conf[key])
69
+ }
70
+ else conf[key] = option
71
+ }
50
72
  }
73
+
74
+ return conf
51
75
  }
@@ -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
+ }