wave-ui 3.11.0 → 3.13.1

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": "3.11.0",
3
+ "version": "3.13.1",
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",
@@ -52,35 +52,35 @@
52
52
  "publish-doc": "npm run build && npm run build-bundle && git add . && git commit -m 'Publish documentation on Github.' && git push && git push --tag"
53
53
  },
54
54
  "devDependencies": {
55
- "@babel/core": "^7.23.9",
56
- "@babel/eslint-parser": "^7.23.10",
55
+ "@babel/core": "^7.24.5",
56
+ "@babel/eslint-parser": "^7.24.5",
57
57
  "@faker-js/faker": "^8.4.1",
58
58
  "@mdi/font": "^6.9.96",
59
- "@tsconfig/recommended": "^1.0.2",
60
- "@typescript-eslint/eslint-plugin": "^6.6.0",
61
- "@typescript-eslint/parser": "^6.6.0",
59
+ "@tsconfig/recommended": "^1.0.6",
60
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
61
+ "@typescript-eslint/parser": "^6.21.0",
62
62
  "@vitejs/plugin-vue": "^5.0.4",
63
- "@vue/compiler-sfc": "3.4.18",
64
- "autoprefixer": "^10.4.17",
65
- "axios": "^1.6.7",
66
- "eslint": "^8.56.0",
67
- "eslint-plugin-vue": "^9.21.1",
63
+ "@vue/compiler-sfc": "3.4.26",
64
+ "autoprefixer": "^10.4.19",
65
+ "axios": "^1.6.8",
66
+ "eslint": "^8.57.0",
67
+ "eslint-plugin-vue": "^9.25.0",
68
68
  "font-awesome": "^4.7.0",
69
69
  "gsap": "^3.12.5",
70
70
  "ionicons": "^4.6.3",
71
71
  "material-design-icons": "^3.0.1",
72
- "postcss": "^8.4.35",
72
+ "postcss": "^8.4.38",
73
73
  "pug": "^3.0.2",
74
74
  "rollup-plugin-delete": "^2.0.0",
75
- "sass": "^1.70.0",
75
+ "sass": "^1.76.0",
76
76
  "simple-syntax-highlighter": "^3.0.2",
77
77
  "splitpanes": "^3.1.5",
78
78
  "standard": "^17.1.0",
79
- "typescript": "^5.2.2",
80
- "vite": "^5.1.1",
79
+ "typescript": "^5.4.5",
80
+ "vite": "^5.2.11",
81
81
  "vite-svg-loader": "^5.1.0",
82
- "vue": "^3.4.18",
83
- "vue-router": "^4.2.5",
82
+ "vue": "^3.4.26",
83
+ "vue-router": "^4.3.2",
84
84
  "vueperslides": "^3.5.1",
85
85
  "vuex": "^4.1.0"
86
86
  },
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-alert(v-if="show" v-on="$attrs" :class="classes")
2
+ .w-alert(v-if="show" :class="classes")
3
3
  //- Add a wrapper around the content when needed.
4
4
  template(v-if="type || icon || dismiss")
5
5
  w-icon.w-alert__icon.mr2(v-if="type || icon") {{ type ? typeIcon : icon }}
@@ -81,12 +81,6 @@ export default {
81
81
  return this.normalize(this.keywords)
82
82
  },
83
83
 
84
- // Keep the autocomplete matching as fast as possible by caching optimized search strings.
85
- // An array of optimized strings.
86
- normalizedSelection () {
87
- return this.selection.map(item => this.normalize(item?.searchable))
88
- },
89
-
90
84
  // Keep the autocomplete matching as fast as possible by caching optimized search strings.
91
85
  optimizedItemsForSearch () {
92
86
  return this.items.map((item, i) => ({
@@ -98,8 +92,7 @@ export default {
98
92
 
99
93
  filteredItems () {
100
94
  let items = this.optimizedItemsForSearch // Array of objects.
101
- const selection = this.normalizedSelection.join(',') // Optimized string of coma separated words.
102
- const isItemNotSelected = item => !selection.includes(item.searchable)
95
+ const isItemNotSelected = item => !this.selection.find(i => i.uid === item.uid)
103
96
 
104
97
  if (this.keywords) {
105
98
  items = items.filter(item => {
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-badge-wrap(v-on="$attrs")
2
+ .w-badge-wrap
3
3
  slot
4
4
  transition(:name="`${transition}`")
5
5
  .w-badge(
@@ -71,20 +71,24 @@ export default {
71
71
  return this.hasRouter ? this.$router.resolve(this.route).href : this.route
72
72
  },
73
73
  listeners () {
74
+ // Extract the potential class & style from v-on listeners. It will still be added from the
75
+ // built-in attributes fallthrough (implicit v-bind="$attrs" when single root node).
76
+ const { class: classes, style, ...attrs } = this.$attrs
77
+
74
78
  // If the button is a router-link, we can't apply events on it since vue-router needs the .native
75
79
  // modifier but it's not available with the v-on directive.
76
80
  // So do a manual router.push if $router is present.
77
81
  // eslint-disable-next-line multiline-ternary
78
82
  return this.route && this.hasRouter && !this.forceLink && !this.externalLink ? {
79
- ...this.$attrs,
83
+ ...attrs,
80
84
  click: e => {
81
- if (this.$attrs.click) this.$attrs.click(e)
85
+ if (attrs.click) attrs.click(e)
82
86
 
83
- this.$router.push(this.route)
87
+ router.push(this.route)
84
88
  e.stopPropagation() // If going to a route, no need to bubble up the event.
85
89
  e.preventDefault()
86
90
  }
87
- } : this.$attrs
91
+ } : attrs
88
92
  },
89
93
  size () {
90
94
  return (
@@ -1,7 +1,6 @@
1
1
  <template lang="pug">
2
2
  component.w-icon(
3
3
  :is="tag || 'i'"
4
- v-on="$attrs"
5
4
  :class="classes"
6
5
  role="icon"
7
6
  aria-hidden="true"
@@ -196,8 +196,9 @@ export default {
196
196
 
197
197
  listeners () {
198
198
  // Remove the events that are fired separately, so they don't fire twice.
199
+ // Also remove class and style which are meant to stay on the wrapper.
199
200
  // eslint-disable-next-line no-unused-vars
200
- const { input, focus, blur, ...listeners } = this.$attrs
201
+ const { input, focus, blur, class: classes, style, ...listeners } = this.$attrs
201
202
  return listeners
202
203
  },
203
204
 
@@ -478,6 +479,7 @@ $inactive-color: #777;
478
479
  align-items: center;
479
480
  background: none;
480
481
  border: none;
482
+ border-radius: inherit; // Mostly for the browser-autofilled appearance.
481
483
  outline: none;
482
484
  padding-left: 2 * $base-increment;
483
485
  padding-right: 2 * $base-increment;
@@ -34,10 +34,11 @@ component(
34
34
  :aria-owns="`w-select-menu--${_.uid}`"
35
35
  :aria-activedescendant="`w-select-menu--${_.uid}_item-1`"
36
36
  :class="inputWrapClasses")
37
- w-icon.w-select__icon.w-select__icon--inner-left(
38
- v-if="innerIconLeft"
39
- tag="label"
40
- @click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
37
+ slot(name="icon-left")
38
+ w-icon.w-select__icon.w-select__icon--inner-left(
39
+ v-if="innerIconLeft"
40
+ tag="label"
41
+ @click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
41
42
  .w-select__selection-slot(v-if="$slots.selection")
42
43
  //- inputValue is always an array.
43
44
  slot(name="selection" :item="multiple ? inputValue : inputValue[0]")
@@ -60,10 +61,11 @@ component(
60
61
  v-if="$slots.default || label"
61
62
  :class="labelClasses")
62
63
  slot {{ label }}
63
- w-icon.w-select__icon.w-select__icon--inner-right(
64
- v-if="innerIconRight"
65
- tag="label"
66
- @click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
64
+ slot(name="icon-right")
65
+ w-icon.w-select__icon.w-select__icon--inner-right(
66
+ v-if="innerIconRight"
67
+ tag="label"
68
+ @click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
67
69
  w-list(
68
70
  ref="w-list"
69
71
  :model-value="inputValue"
@@ -29,7 +29,7 @@ component(
29
29
  slot {{ label }}
30
30
  .w-switch__input(
31
31
  @click="$refs.input.focus();$refs.input.click()"
32
- v-on="$attrs"
32
+ v-on="listeners"
33
33
  :class="inputClasses")
34
34
  .w-switch__track(v-if="$slots.track")
35
35
  slot(name="track")
@@ -84,6 +84,13 @@ export default {
84
84
  },
85
85
 
86
86
  computed: {
87
+ listeners () {
88
+ // Remove the events that are fired separately, so they don't fire twice.
89
+ // Also remove class and style which are meant to stay on the wrapper.
90
+ // eslint-disable-next-line no-unused-vars
91
+ const { click, class: classes, style, ...listeners } = this.$attrs
92
+ return listeners
93
+ },
87
94
  hasLabel () {
88
95
  return this.label || this.$slots.default
89
96
  },
@@ -150,6 +157,7 @@ $outline-width: 2px;
150
157
  align-items: center;
151
158
  vertical-align: middle;
152
159
  cursor: pointer;
160
+ -webkit-tap-highlight-color: transparent;
153
161
 
154
162
  @include themeable;
155
163
 
@@ -157,7 +165,6 @@ $outline-width: 2px;
157
165
  &--disabled, &--readonly {
158
166
  cursor: not-allowed;
159
167
  touch-action: initial;
160
- -webkit-tap-highlight-color: transparent;
161
168
  }
162
169
 
163
170
  // Hidden checkbox.
@@ -609,16 +609,33 @@ export default {
609
609
  })
610
610
  },
611
611
 
612
+ /**
613
+ * Updates the pagination object and fills up missing variables to always maintain the paginationConfig
614
+ * object accurate for external use (read and write).
615
+ * The following vars will always be up to date and if one changes from outside the rest of them
616
+ * will update accordingly: itemsPerPage, itemsPerPageOptions, start, end, page, total.
617
+ *
618
+ * @param {Object} config The config object defining the pagination.
619
+ * This object can have at most itemsPerPage, page, total, and it will define the start, end and
620
+ * pagesCount from the given or current itemsPerPage, page and total.
621
+ * - If a total is given for update, trust it blindly (could come from a backend), and recompute
622
+ * the rest as long as itemsPerPage is defined.
623
+ * - If a page is given for update, it will navigate to that page.
624
+ * - If an itemsPerPage is given for update, it will navigate to that page.
625
+ */
612
626
  updatePaginationConfig ({ itemsPerPage, page, total }) {
613
627
  if (total) this.paginationConfig.total = total
614
628
  if (itemsPerPage !== undefined) {
615
629
  this.paginationConfig.itemsPerPage = itemsPerPage
616
630
  itemsPerPage = itemsPerPage || this.paginationConfig.total // If `0`, take all the results.
617
631
  this.paginationConfig.page = page || this.paginationConfig.page || 1
632
+
618
633
  page = this.paginationConfig.page // Shorthand var for next lines.
619
634
  total = this.paginationConfig.total // Shorthand var for next lines.
635
+ const itemsInAllPages = itemsPerPage * page
620
636
  this.paginationConfig.start = 1
621
- this.paginationConfig.end = total >= (itemsPerPage * page) ? (itemsPerPage * page) : (total % (itemsPerPage * page))
637
+ this.paginationConfig.end = total >= itemsInAllPages ? itemsInAllPages : (total % itemsInAllPages)
638
+
622
639
  this.paginationConfig.pagesCount = Math.ceil(total / itemsPerPage)
623
640
  }
624
641
  if (page) this.goToPage(page)
@@ -1,6 +1,5 @@
1
1
  <template lang="pug">
2
2
  span.w-tag(
3
- v-on="$attrs"
4
3
  @click="$emit('update:modelValue', !modelValue);$emit('input', !modelValue)"
5
4
  @keypress.enter="$emit('update:modelValue', !modelValue);$emit('input', !modelValue)"
6
5
  :class="classes"
@@ -17,11 +17,12 @@ component(
17
17
 
18
18
  //- Input wrapper.
19
19
  .w-textarea__textarea-wrap(:class="inputWrapClasses")
20
- w-icon.w-textarea__icon.w-textarea__icon--inner-left(
21
- v-if="innerIconLeft"
22
- tag="label"
23
- :for="`w-textarea--${_.uid}`"
24
- @click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
20
+ slot(name="icon-left" :input-id="`w-textarea--${_.uid}`")
21
+ w-icon.w-textarea__icon.w-textarea__icon--inner-left(
22
+ v-if="innerIconLeft"
23
+ tag="label"
24
+ :for="`w-textarea--${_.uid}`"
25
+ @click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
25
26
  textarea.w-textarea__textarea(
26
27
  ref="textarea"
27
28
  v-model="inputValue"
@@ -44,11 +45,12 @@ component(
44
45
  v-if="$slots.default || label"
45
46
  :class="labelClasses")
46
47
  slot {{ label }}
47
- w-icon.w-textarea__icon.w-textarea__icon--inner-right(
48
- v-if="innerIconRight"
49
- tag="label"
50
- :for="`w-textarea--${_.uid}`"
51
- @click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
48
+ slot(name="icon-right" :input-id="`w-textarea--${_.uid}`")
49
+ w-icon.w-textarea__icon.w-textarea__icon--inner-right(
50
+ v-if="innerIconRight"
51
+ tag="label"
52
+ :for="`w-textarea--${_.uid}`"
53
+ @click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
52
54
 
53
55
  //- Right label.
54
56
  template(v-if="labelPosition === 'right'")
@@ -111,8 +113,9 @@ export default {
111
113
  computed: {
112
114
  listeners () {
113
115
  // Remove the events that are fired separately, so they don't fire twice.
116
+ // Also remove class and style which are meant to stay on the wrapper.
114
117
  // eslint-disable-next-line no-unused-vars
115
- const { input, focus, blur, ...listeners } = this.$attrs
118
+ const { input, focus, blur, class: classes, style, ...listeners } = this.$attrs
116
119
  return listeners
117
120
  },
118
121
  hasValue () {
@@ -85,7 +85,7 @@ export default class WaveUI {
85
85
  document.documentElement.setAttribute('data-theme', theme)
86
86
  document.head.querySelector('#wave-ui-colors')?.remove?.()
87
87
  const themeColors = this.config.colors[this.theme]
88
- injectColorsCSSInDOM(themeColors)
88
+ injectColorsCSSInDOM(themeColors, this.config.css.colorShadeCssVariables)
89
89
  this.colors = flattenColors(themeColors, colorPalette)
90
90
  }
91
91
  }
@@ -14,6 +14,10 @@ const config = reactive({
14
14
  // Note: the color palette shades are always generated separately from SCSS.
15
15
  colorShades: true,
16
16
 
17
+ // Generate CSS variables for color shades.
18
+ // Note: colorShades must be enabled for this to work.
19
+ colorShadeCssVariables: false,
20
+
17
21
  // Generate palette colors and palette color shades.
18
22
  // Can't have this option: color palette is generated via SCSS in colors.scss.
19
23
  // colorPalette: true,
@@ -13,7 +13,7 @@ let currentBreakpoint = null
13
13
  // :root {[color1-variable], [color2-variable]}
14
14
  // .color1--bg {background-color: [color1-variable]}
15
15
  // .color1 {color: [color1-variable]}
16
- const generateColors = themeColors => {
16
+ const generateColors = (themeColors, generateShadeCssVariables) => {
17
17
  let styles = ''
18
18
  const cssVariables = {}
19
19
 
@@ -42,6 +42,9 @@ const generateColors = themeColors => {
42
42
  // That only makes sense when there are 2 colors on the same element: e.g. `span.primary.error`.
43
43
  const allColors = { ...colors, info, warning, success, error }
44
44
  for (const colorName in allColors) cssVariables[colorName] = allColors[colorName]
45
+ if (generateShadeCssVariables) {
46
+ for (const colorName in shades) cssVariables[colorName] = shades[colorName]
47
+ }
45
48
  let cssVariablesString = ''
46
49
  Object.entries(cssVariables).forEach(([colorName, colorHex]) => {
47
50
  cssVariablesString += `--w-${colorName}-color: ${colorHex};`
@@ -269,12 +272,12 @@ export const injectCSSInDOM = $waveui => {
269
272
  window.addEventListener('resize', () => getBreakpoint($waveui))
270
273
  }
271
274
 
272
- export const injectColorsCSSInDOM = themeColors => {
275
+ export const injectColorsCSSInDOM = (themeColors, generateShadeCssVariables) => {
273
276
  // Inject global dynamic CSS classes in document head.
274
277
  if (!document.getElementById('wave-ui-colors')) {
275
278
  const css = document.createElement('style')
276
279
  css.id = 'wave-ui-colors'
277
- css.innerHTML = generateColors(themeColors)
280
+ css.innerHTML = generateColors(themeColors, generateShadeCssVariables)
278
281
 
279
282
  const firstStyle = document.head.querySelectorAll('style,link[rel="stylesheet"]')[0]
280
283
  if (firstStyle) firstStyle.before(css)