wave-ui 3.27.2 → 3.28.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 (32) hide show
  1. package/dist/types/types/$waveui.d.ts +6 -0
  2. package/dist/types/types/components/WAccordion.d.ts +7 -0
  3. package/dist/types/types/components/WBreadcrumbs.d.ts +7 -0
  4. package/dist/types/types/components/WButton.d.ts +7 -0
  5. package/dist/types/types/components/WList.d.ts +7 -0
  6. package/dist/types/types/components/WScrollable.d.ts +143 -0
  7. package/dist/types/types/components/WScrollable.js +2 -0
  8. package/dist/types/types/components/WTabs.d.ts +7 -0
  9. package/dist/types/types/components/WTag.d.ts +7 -0
  10. package/dist/types/types/components/index.d.ts +1 -0
  11. package/dist/wave-ui.cjs.js +3 -3
  12. package/dist/wave-ui.css +1 -1
  13. package/dist/wave-ui.esm.js +1392 -925
  14. package/dist/wave-ui.umd.js +3 -3
  15. package/package.json +6 -6
  16. package/src/wave-ui/components/w-accordion/index.vue +5 -1
  17. package/src/wave-ui/components/w-accordion/item.vue +42 -12
  18. package/src/wave-ui/components/w-breadcrumbs.vue +13 -2
  19. package/src/wave-ui/components/w-button/button.vue +15 -1
  20. package/src/wave-ui/components/w-button/index.vue +2 -1
  21. package/src/wave-ui/components/w-list.vue +12 -0
  22. package/src/wave-ui/components/w-scrollable.vue +667 -94
  23. package/src/wave-ui/components/w-tabs/index.vue +10 -0
  24. package/src/wave-ui/components/w-tag.vue +14 -0
  25. package/src/wave-ui/core.js +2 -0
  26. package/src/wave-ui/mixins/ripple.js +39 -0
  27. package/src/wave-ui/scss/_ripple.scss +37 -0
  28. package/src/wave-ui/scss/index.scss +1 -0
  29. package/src/wave-ui/scss/variables/_variables.scss +0 -2
  30. package/src/wave-ui/utils/config.js +2 -0
  31. package/src/wave-ui/utils/ripple.js +71 -0
  32. package/src/wave-ui/utils/wave-ripple-directive.js +40 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-ui",
3
- "version": "3.27.2",
3
+ "version": "3.28.0",
4
4
  "description": "A UI framework for Vue.js 3 (and 2) with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "homepage": "https://antoniandre.github.io/wave-ui",
@@ -50,13 +50,13 @@
50
50
  ],
51
51
  "devDependencies": {
52
52
  "@babel/core": "^7.29.0",
53
- "@biomejs/biome": "^2.4.12",
53
+ "@biomejs/biome": "^2.4.13",
54
54
  "@faker-js/faker": "^10.4.0",
55
55
  "@mdi/font": "^7.4.47",
56
56
  "@tsconfig/recommended": "^1.0.13",
57
57
  "@vitejs/plugin-vue": "^6.0.6",
58
58
  "autoprefixer": "^10.5.0",
59
- "axios": "^1.15.1",
59
+ "axios": "^1.15.2",
60
60
  "font-awesome": "^4.7.0",
61
61
  "globals": "^17.5.0",
62
62
  "gsap": "^3.15.0",
@@ -69,10 +69,10 @@
69
69
  "simple-syntax-highlighter": "^3.1.1",
70
70
  "splitpanes": "^4.0.4",
71
71
  "typescript": "^6.0.3",
72
- "vite": "^8.0.9",
72
+ "vite": "^8.0.10",
73
73
  "vite-svg-loader": "^5.1.1",
74
- "vue": "^3.5.32",
75
- "vue-router": "^5.0.4",
74
+ "vue": "^3.5.33",
75
+ "vue-router": "^5.0.6",
76
76
  "vueperslides": "^3.6.0",
77
77
  "vuex": "^4.1.0"
78
78
  },
@@ -47,11 +47,14 @@
47
47
  <script>
48
48
  import { objectifyClasses } from '../../utils/index'
49
49
  import { consoleError } from '../../utils/console'
50
+ import RippleMixin from '../../mixins/ripple'
50
51
  import WAccordionItem from './item.vue'
51
52
 
52
53
  export default {
53
54
  name: 'w-accordion',
54
55
 
56
+ mixins: [RippleMixin],
57
+
55
58
  props: {
56
59
  modelValue: { type: Array },
57
60
  color: { type: String },
@@ -94,7 +97,8 @@ export default {
94
97
  options: this.$props,
95
98
  registerItem: this.registerItem,
96
99
  unregisterItem: this.unregisterItem,
97
- getAccordionItem: this.getAccordionItem
100
+ getAccordionItem: this.getAccordionItem,
101
+ getAccordionNoRipple: () => this.noRipple
98
102
  }
99
103
  },
100
104
 
@@ -2,10 +2,11 @@
2
2
  .w-accordion__item(:class="itemClasses" :aria-expanded="accordionItem._expanded ? 'true' : 'false'")
3
3
  .w-accordion__item-title(
4
4
  @click="!accordionItem._disabled && toggleItem(accordionItem, $event)"
5
+ @pointerdown="onAccordionTitlePointerDown"
5
6
  @focus="$emit('focus', (accordionItem))"
6
7
  @keypress.enter="!accordionItem._disabled && toggleItem(accordionItem, $event)"
7
8
  :tabindex="!accordionItem._disabled && 0"
8
- :class="titleClasses")
9
+ :class="accordionTitleClasses")
9
10
  //- Expand icon on left.
10
11
  w-button.w-accordion__expand-icon(
11
12
  v-if="options.expandIcon && !options.expandIconRight"
@@ -70,11 +71,15 @@
70
71
 
71
72
  <script>
72
73
  import { useId } from 'vue'
74
+ import RippleMixin from '../../mixins/ripple'
75
+ import { isRippleEnabled } from '../../utils/ripple'
73
76
  import AccordionContent from './accordion-content.vue'
74
77
 
75
78
  export default {
76
79
  name: 'w-accordion-item',
77
80
 
81
+ mixins: [RippleMixin],
82
+
78
83
  setup () {
79
84
  return { accordionItemUid: useId() }
80
85
  },
@@ -88,21 +93,40 @@ export default {
88
93
  disabled: { type: Boolean }
89
94
  },
90
95
 
91
- inject: [
92
- 'options',
93
- 'titleClasses',
94
- 'contentClasses',
95
- 'onItemToggle',
96
- 'onEndOfCollapse',
97
- 'getOriginalItem',
98
- 'getAccordionItem',
99
- 'registerItem',
100
- 'unregisterItem'
101
- ],
96
+ inject: {
97
+ options: { from: 'options' },
98
+ titleClasses: { from: 'titleClasses' },
99
+ contentClasses: { from: 'contentClasses' },
100
+ onItemToggle: { from: 'onItemToggle' },
101
+ onEndOfCollapse: { from: 'onEndOfCollapse' },
102
+ getOriginalItem: { from: 'getOriginalItem' },
103
+ getAccordionItem: { from: 'getAccordionItem' },
104
+ registerItem: { from: 'registerItem' },
105
+ unregisterItem: { from: 'unregisterItem' },
106
+ getAccordionNoRipple: { from: 'getAccordionNoRipple', default: () => undefined }
107
+ },
102
108
 
103
109
  emits: ['focus'],
104
110
 
105
111
  computed: {
112
+ /** Per-item noRipple override, else parent `w-accordion` noRipple, else global config. */
113
+ rippleActive () {
114
+ let resolvedNoRipple
115
+ if (typeof this.noRipple === 'boolean') resolvedNoRipple = this.noRipple
116
+ else {
117
+ const p = this.getAccordionNoRipple?.()
118
+ resolvedNoRipple = typeof p === 'boolean' ? p : undefined
119
+ }
120
+ return isRippleEnabled(resolvedNoRipple ? false : undefined, this.$waveui)
121
+ },
122
+
123
+ accordionTitleClasses () {
124
+ return {
125
+ ...this.titleClasses,
126
+ 'w-ripple': this.rippleActive
127
+ }
128
+ },
129
+
106
130
  accordionItem: {
107
131
  get () {
108
132
  return this.getAccordionItem(this.accordionItemUid)
@@ -119,6 +143,12 @@ export default {
119
143
  },
120
144
 
121
145
  methods: {
146
+ onAccordionTitlePointerDown (e) {
147
+ if (this.accordionItem._disabled) return
148
+ if (e.target.closest?.('.w-accordion__expand-icon')) return
149
+ this.onRipple(e)
150
+ },
151
+
122
152
  toggleItem (item, e) {
123
153
  item._expanded = !item._expanded
124
154
 
@@ -20,7 +20,8 @@
20
20
  :is="hasRouter ? 'router-link' : 'a'"
21
21
  :to="hasRouter && item[itemRouteKey]"
22
22
  :href="item[itemRouteKey]"
23
- :class="color || null")
23
+ :class="breadcrumbLinkClasses"
24
+ @pointerdown="onRipple")
24
25
  slot(name="item" :item="item" :index="i + 1" :isLast="i === items.length - 1")
25
26
  component.w-breadcrumbs__item(
26
27
  v-else
@@ -29,7 +30,8 @@
29
30
  :to="hasRouter && item[itemRouteKey]"
30
31
  :href="item[itemRouteKey]"
31
32
  v-html="item[itemLabelKey]"
32
- :class="color || null")
33
+ :class="breadcrumbLinkClasses"
34
+ @pointerdown="onRipple")
33
35
 
34
36
  //- Current page when linkLastItem is false.
35
37
  slot(
@@ -43,8 +45,13 @@
43
45
  </template>
44
46
 
45
47
  <script>
48
+ import RippleMixin from '../mixins/ripple'
49
+
46
50
  export default {
47
51
  name: 'w-breadcrumbs',
52
+
53
+ mixins: [RippleMixin],
54
+
48
55
  props: {
49
56
  items: { type: Array, required: true },
50
57
  linkLastItem: { type: Boolean },
@@ -63,6 +70,10 @@ export default {
63
70
  emits: [],
64
71
 
65
72
  computed: {
73
+ breadcrumbLinkClasses () {
74
+ return [this.color || null, { 'w-ripple': this.rippleActive }]
75
+ },
76
+
66
77
  hasRouter () {
67
78
  return '$router' in this
68
79
  },
@@ -6,7 +6,8 @@ component.w-button(
6
6
  :class="classes"
7
7
  :disabled="!!disabled || null"
8
8
  v-bind="attrs"
9
- :style="styles")
9
+ :style="styles"
10
+ @pointerdown="onPointerDownRipple")
10
11
  w-icon(v-if="icon" v-bind="iconProps || {}") {{ icon }}
11
12
  slot(v-else)
12
13
  transition(name="scale-fade")
@@ -22,11 +23,15 @@ component.w-button(
22
23
  </template>
23
24
 
24
25
  <script>
26
+ import RippleMixin from '../../mixins/ripple'
27
+
25
28
  export default {
26
29
  // Fully handle the attrs and listeners manually for the case of a router link that has both a
27
30
  // route and onClick.
28
31
  inheritAttrs: false,
29
32
 
33
+ mixins: [RippleMixin],
34
+
30
35
  props: {
31
36
  color: { type: String },
32
37
  bgColor: { type: String },
@@ -67,6 +72,13 @@ export default {
67
72
 
68
73
  emits: [],
69
74
 
75
+ methods: {
76
+ onPointerDownRipple (e) {
77
+ if (this.disabled || this.loading || !this.rippleActive) return
78
+ this.onRipple(e)
79
+ }
80
+ },
81
+
70
82
  computed: {
71
83
  hasRouter () {
72
84
  return '$router' in this
@@ -112,6 +124,7 @@ export default {
112
124
  },
113
125
  classes () {
114
126
  return {
127
+ 'w-ripple': this.rippleActive,
115
128
  // If no color / bg color is set, set a primary color by default.
116
129
  'primary--bg': !this.bgColor && !this.color && !(this.outline || this.text),
117
130
  primary: !this.bgColor && !this.color && !this.dark && (this.outline || this.text),
@@ -246,6 +259,7 @@ $spinner-size: 40;
246
259
  content: '';
247
260
  position: absolute;
248
261
  inset: 0;
262
+ z-index: 0;
249
263
  opacity: 0;
250
264
  background-color: #000;
251
265
  border-radius: inherit;
@@ -53,7 +53,8 @@ export default {
53
53
  sm: { type: Boolean },
54
54
  md: { type: Boolean },
55
55
  lg: { type: Boolean },
56
- xl: { type: Boolean }
56
+ xl: { type: Boolean },
57
+ noRipple: { type: Boolean, default: undefined }
57
58
  },
58
59
 
59
60
  components: { ButtonPartial },
@@ -44,10 +44,13 @@ ul.w-list(:class="classes")
44
44
 
45
45
  <script>
46
46
  import { useId } from 'vue'
47
+ import RippleMixin from '../mixins/ripple'
47
48
 
48
49
  export default {
49
50
  name: 'w-list',
50
51
 
52
+ mixins: [RippleMixin],
53
+
51
54
  setup () {
52
55
  return { waveUiUseId: useId() }
53
56
  },
@@ -161,7 +164,13 @@ export default {
161
164
  },
162
165
 
163
166
  liLabelClasses (item) {
167
+ const rippleHost =
168
+ this.rippleActive &&
169
+ !item.disabled &&
170
+ (this.checklist || this.isSelectable || (this.nav && item[this.itemRouteKey]))
171
+
164
172
  return {
173
+ 'w-ripple': rippleHost,
165
174
  'w-list__item-label--disabled': item.disabled || (this.nav && !item[this.itemRouteKey] && !item.children),
166
175
  'w-list__item-label--active': (this.isSelectable && item._selected) || null,
167
176
  'w-list__item-label--focused': item._focused,
@@ -188,6 +197,7 @@ export default {
188
197
  // If selectable list, on mousedown select the item.
189
198
  const mousedown = this.isSelectable && (e => {
190
199
  e.stopPropagation()
200
+ this.onRipple(e)
191
201
  !li.disabled && this.selectItem(li)
192
202
  })
193
203
  // If selectable list, on enter key press select item.
@@ -230,6 +240,7 @@ export default {
230
240
  props.onFocus = () => (li._focused = true)
231
241
  props.onBlur = () => (li._focused = false)
232
242
  props.onInput = value => this.selectItem(li, value)
243
+ props.onPointerdown = e => this.onRipple(e)
233
244
  // When clicking on the checkbox component wrapper, trigger a focus & click on the checkbox.
234
245
  props.onClick = e => {
235
246
  const checkbox = e.target.querySelector('input[type="checkbox"]')
@@ -250,6 +261,7 @@ export default {
250
261
  if (!li.disabled && li[this.itemRouteKey]) {
251
262
  props.onKeydown = keydown
252
263
  props.onMousedown = mousedown
264
+ props.onPointerdown = e => this.onRipple(e)
253
265
 
254
266
  if (this.$router) {
255
267
  props.to = li[this.itemRouteKey]