wave-ui 3.27.1 → 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.
- package/dist/types/types/$waveui.d.ts +6 -0
- package/dist/types/types/components/WAccordion.d.ts +7 -0
- package/dist/types/types/components/WBreadcrumbs.d.ts +7 -0
- package/dist/types/types/components/WButton.d.ts +7 -0
- package/dist/types/types/components/WList.d.ts +7 -0
- package/dist/types/types/components/WScrollable.d.ts +143 -0
- package/dist/types/types/components/WScrollable.js +2 -0
- package/dist/types/types/components/WTabs.d.ts +7 -0
- package/dist/types/types/components/WTag.d.ts +7 -0
- package/dist/types/types/components/index.d.ts +1 -0
- package/dist/wave-ui.cjs.js +3 -3
- package/dist/wave-ui.css +1 -1
- package/dist/wave-ui.esm.js +1440 -939
- package/dist/wave-ui.umd.js +3 -3
- package/package.json +6 -6
- package/src/wave-ui/components/w-accordion/index.vue +5 -1
- package/src/wave-ui/components/w-accordion/item.vue +42 -12
- package/src/wave-ui/components/w-breadcrumbs.vue +13 -2
- package/src/wave-ui/components/w-button/button.vue +15 -1
- package/src/wave-ui/components/w-button/index.vue +2 -1
- package/src/wave-ui/components/w-checkbox.vue +5 -1
- package/src/wave-ui/components/w-checkboxes.vue +5 -1
- package/src/wave-ui/components/w-input.vue +5 -1
- package/src/wave-ui/components/w-list.vue +12 -0
- package/src/wave-ui/components/w-radio.vue +6 -1
- package/src/wave-ui/components/w-radios.vue +5 -1
- package/src/wave-ui/components/w-rating.vue +5 -1
- package/src/wave-ui/components/w-scrollable.vue +667 -94
- package/src/wave-ui/components/w-select.vue +11 -7
- package/src/wave-ui/components/w-slider.vue +5 -1
- package/src/wave-ui/components/w-switch.vue +5 -1
- package/src/wave-ui/components/w-tabs/index.vue +10 -0
- package/src/wave-ui/components/w-tag.vue +14 -0
- package/src/wave-ui/components/w-textarea.vue +5 -1
- package/src/wave-ui/core.js +2 -0
- package/src/wave-ui/mixins/form-elements.js +5 -8
- package/src/wave-ui/mixins/ripple.js +39 -0
- package/src/wave-ui/scss/_ripple.scss +37 -0
- package/src/wave-ui/scss/index.scss +1 -0
- package/src/wave-ui/scss/variables/_variables.scss +0 -2
- package/src/wave-ui/utils/config.js +2 -0
- package/src/wave-ui/utils/ripple.js +71 -0
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
72
|
+
"vite": "^8.0.10",
|
|
73
73
|
"vite-svg-loader": "^5.1.1",
|
|
74
|
-
"vue": "^3.5.
|
|
75
|
-
"vue-router": "^5.0.
|
|
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="
|
|
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="
|
|
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="
|
|
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;
|
|
@@ -49,12 +49,16 @@ component(
|
|
|
49
49
|
</template>
|
|
50
50
|
|
|
51
51
|
<script>
|
|
52
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
52
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
53
53
|
|
|
54
54
|
export default {
|
|
55
55
|
name: 'w-checkbox',
|
|
56
56
|
mixins: [FormElementMixin],
|
|
57
57
|
|
|
58
|
+
setup () {
|
|
59
|
+
return useWaveUiFormIds()
|
|
60
|
+
},
|
|
61
|
+
|
|
58
62
|
inject: {
|
|
59
63
|
wCheckboxes: { default: null }
|
|
60
64
|
},
|
|
@@ -31,12 +31,16 @@ component(
|
|
|
31
31
|
|
|
32
32
|
<script>
|
|
33
33
|
import { reactive } from 'vue'
|
|
34
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
34
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
35
35
|
|
|
36
36
|
export default {
|
|
37
37
|
name: 'w-checkboxes',
|
|
38
38
|
mixins: [FormElementMixin],
|
|
39
39
|
|
|
40
|
+
setup () {
|
|
41
|
+
return useWaveUiFormIds()
|
|
42
|
+
},
|
|
43
|
+
|
|
40
44
|
props: {
|
|
41
45
|
items: { type: Array, required: true }, // All the possible options.
|
|
42
46
|
modelValue: { type: Array }, // v-model on selected option.
|
|
@@ -128,7 +128,7 @@ component(
|
|
|
128
128
|
* - option to fit to the content using contenteditable div
|
|
129
129
|
**/
|
|
130
130
|
|
|
131
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
131
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
132
132
|
import { reactive } from 'vue'
|
|
133
133
|
|
|
134
134
|
export default {
|
|
@@ -136,6 +136,10 @@ export default {
|
|
|
136
136
|
mixins: [FormElementMixin],
|
|
137
137
|
inheritAttrs: false, // The attrs should only be added to the input not the wrapper.
|
|
138
138
|
|
|
139
|
+
setup () {
|
|
140
|
+
return useWaveUiFormIds()
|
|
141
|
+
},
|
|
142
|
+
|
|
139
143
|
props: {
|
|
140
144
|
modelValue: { default: '' },
|
|
141
145
|
type: { type: String, default: 'text' },
|
|
@@ -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]
|
|
@@ -47,11 +47,16 @@ component(
|
|
|
47
47
|
</template>
|
|
48
48
|
|
|
49
49
|
<script>
|
|
50
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
50
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
51
51
|
|
|
52
52
|
export default {
|
|
53
53
|
name: 'w-radio',
|
|
54
54
|
mixins: [FormElementMixin],
|
|
55
|
+
|
|
56
|
+
setup () {
|
|
57
|
+
return useWaveUiFormIds()
|
|
58
|
+
},
|
|
59
|
+
|
|
55
60
|
inject: { wRadios: { default: null } },
|
|
56
61
|
|
|
57
62
|
props: {
|
|
@@ -30,12 +30,16 @@ component(
|
|
|
30
30
|
</template>
|
|
31
31
|
|
|
32
32
|
<script>
|
|
33
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
33
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
34
34
|
|
|
35
35
|
export default {
|
|
36
36
|
name: 'w-radios',
|
|
37
37
|
mixins: [FormElementMixin],
|
|
38
38
|
|
|
39
|
+
setup () {
|
|
40
|
+
return useWaveUiFormIds()
|
|
41
|
+
},
|
|
42
|
+
|
|
39
43
|
props: {
|
|
40
44
|
items: { type: Array, required: true }, // All the possible options.
|
|
41
45
|
modelValue: { type: [String, Number, Boolean] }, // v-model on selected option.
|
|
@@ -29,12 +29,16 @@ component(
|
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
31
|
<script>
|
|
32
|
-
import FormElementMixin from '../mixins/form-elements'
|
|
32
|
+
import FormElementMixin, { useWaveUiFormIds } from '../mixins/form-elements'
|
|
33
33
|
|
|
34
34
|
export default {
|
|
35
35
|
name: 'w-rating',
|
|
36
36
|
mixins: [FormElementMixin],
|
|
37
37
|
|
|
38
|
+
setup () {
|
|
39
|
+
return useWaveUiFormIds()
|
|
40
|
+
},
|
|
41
|
+
|
|
38
42
|
props: {
|
|
39
43
|
modelValue: {},
|
|
40
44
|
max: { type: [Number, String], default: 5 },
|