wave-ui 3.26.1 → 3.27.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/components/WForm.d.ts +2 -1
- package/dist/types/types/components/WFormElement.d.ts +6 -0
- package/dist/wave-ui.cjs.js +3 -3
- package/dist/wave-ui.esm.js +725 -684
- package/dist/wave-ui.umd.js +3 -3
- package/package.json +2 -2
- package/src/wave-ui/components/w-accordion/item.vue +8 -3
- package/src/wave-ui/components/w-checkbox.vue +8 -8
- package/src/wave-ui/components/w-checkboxes.vue +2 -2
- package/src/wave-ui/components/w-form-element.vue +10 -1
- package/src/wave-ui/components/w-form.vue +3 -2
- package/src/wave-ui/components/w-input.vue +13 -13
- package/src/wave-ui/components/w-list.vue +8 -1
- package/src/wave-ui/components/w-radio.vue +8 -8
- package/src/wave-ui/components/w-radios.vue +2 -2
- package/src/wave-ui/components/w-rating.vue +4 -4
- package/src/wave-ui/components/w-select.vue +12 -7
- package/src/wave-ui/components/w-slider.vue +14 -9
- package/src/wave-ui/components/w-switch.vue +6 -6
- package/src/wave-ui/components/w-tabs/index.vue +7 -4
- package/src/wave-ui/components/w-textarea.vue +10 -10
- package/src/wave-ui/components/w-tooltip.vue +6 -1
- package/src/wave-ui/mixins/form-elements.js +21 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.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",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"vuex": "^4.1.0"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
|
-
"vue": "^3.
|
|
80
|
+
"vue": "^3.5.0"
|
|
81
81
|
},
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=16.0.0",
|
|
@@ -69,11 +69,16 @@
|
|
|
69
69
|
</template>
|
|
70
70
|
|
|
71
71
|
<script>
|
|
72
|
+
import { useId } from 'vue'
|
|
72
73
|
import AccordionContent from './accordion-content.vue'
|
|
73
74
|
|
|
74
75
|
export default {
|
|
75
76
|
name: 'w-accordion-item',
|
|
76
77
|
|
|
78
|
+
setup () {
|
|
79
|
+
return { accordionItemUid: useId() }
|
|
80
|
+
},
|
|
81
|
+
|
|
77
82
|
components: { AccordionContent },
|
|
78
83
|
|
|
79
84
|
props: {
|
|
@@ -100,7 +105,7 @@ export default {
|
|
|
100
105
|
computed: {
|
|
101
106
|
accordionItem: {
|
|
102
107
|
get () {
|
|
103
|
-
return this.getAccordionItem(this.
|
|
108
|
+
return this.getAccordionItem(this.accordionItemUid)
|
|
104
109
|
},
|
|
105
110
|
set () {}
|
|
106
111
|
},
|
|
@@ -130,7 +135,7 @@ export default {
|
|
|
130
135
|
created () {
|
|
131
136
|
// Register this item to the w-accordion component.
|
|
132
137
|
this.registerItem({
|
|
133
|
-
_cuid: this.
|
|
138
|
+
_cuid: this.accordionItemUid,
|
|
134
139
|
_index: 0,
|
|
135
140
|
_expanded: this.expanded,
|
|
136
141
|
_disabled: this.disabled,
|
|
@@ -140,7 +145,7 @@ export default {
|
|
|
140
145
|
},
|
|
141
146
|
|
|
142
147
|
beforeUnmount () {
|
|
143
|
-
this.unregisterItem(this.
|
|
148
|
+
this.unregisterItem(this.accordionItemUid)
|
|
144
149
|
}
|
|
145
150
|
}
|
|
146
151
|
</script>
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister && !wCheckboxes ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: isChecked, disabled: isDisabled, readonly: isReadonly }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: isChecked, disabled: isDisabled, readonly: isReadonly, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="$emit('update:modelValue', isChecked = null);$emit('input', null)"
|
|
8
8
|
:class="classes")
|
|
9
9
|
input(
|
|
10
10
|
ref="input"
|
|
11
|
-
:id="
|
|
11
|
+
:id="inputId"
|
|
12
12
|
type="checkbox"
|
|
13
13
|
:name="inputName"
|
|
14
14
|
:checked="isChecked || null"
|
|
@@ -24,12 +24,12 @@ component(
|
|
|
24
24
|
template(v-if="hasLabel && labelOnLeft")
|
|
25
25
|
label.w-checkbox__label.w-form-el-shakable.pr2(
|
|
26
26
|
v-if="$slots.default"
|
|
27
|
-
:for="
|
|
27
|
+
:for="inputId"
|
|
28
28
|
:class="labelClasses")
|
|
29
29
|
slot {{ label }}
|
|
30
30
|
label.w-checkbox__label.w-form-el-shakable.pr2(
|
|
31
31
|
v-else-if="label"
|
|
32
|
-
:for="
|
|
32
|
+
:for="inputId"
|
|
33
33
|
:class="labelClasses"
|
|
34
34
|
v-html="label")
|
|
35
35
|
.w-checkbox__input(@click="$refs.input.focus();$refs.input.click()" :class="this.color")
|
|
@@ -38,12 +38,12 @@ component(
|
|
|
38
38
|
template(v-if="hasLabel && !labelOnLeft")
|
|
39
39
|
label.w-checkbox__label.w-form-el-shakable.pl2(
|
|
40
40
|
v-if="$slots.default"
|
|
41
|
-
:for="
|
|
41
|
+
:for="inputId"
|
|
42
42
|
:class="labelClasses")
|
|
43
43
|
slot {{ label }}
|
|
44
44
|
label.w-checkbox__label.w-form-el-shakable.pl2(
|
|
45
45
|
v-else-if="label"
|
|
46
|
-
:for="
|
|
46
|
+
:for="inputId"
|
|
47
47
|
:class="labelClasses"
|
|
48
48
|
v-html="label")
|
|
49
49
|
</template>
|
|
@@ -73,8 +73,8 @@ export default {
|
|
|
73
73
|
round: { type: Boolean },
|
|
74
74
|
dark: { type: Boolean },
|
|
75
75
|
light: { type: Boolean }
|
|
76
|
-
// Props from mixin: name, disabled, readonly, required, tabindex, validators.
|
|
77
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
76
|
+
// Props from mixin: id, name, disabled, readonly, required, tabindex, validators.
|
|
77
|
+
// Computed from mixin: inputId, inputName, isDisabled & isReadonly.
|
|
78
78
|
},
|
|
79
79
|
|
|
80
80
|
emits: ['input', 'update:modelValue', 'focus', 'blur'],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: checkboxItems.some(item => item._isChecked), disabled: isDisabled }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: checkboxItems.some(item => item._isChecked), disabled: isDisabled, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="reset"
|
|
8
8
|
:column="!inline"
|
|
@@ -51,7 +51,7 @@ export default {
|
|
|
51
51
|
round: { type: Boolean },
|
|
52
52
|
color: { type: String, default: 'primary' },
|
|
53
53
|
labelColor: { type: String, default: 'primary' }
|
|
54
|
-
// Props from mixin: name, disabled, readonly, required, validators.
|
|
54
|
+
// Props from mixin: id, name, disabled, readonly, required, validators.
|
|
55
55
|
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
56
56
|
},
|
|
57
57
|
|
|
@@ -20,6 +20,8 @@ export default {
|
|
|
20
20
|
readonly: { type: Boolean },
|
|
21
21
|
inputValue: { required: true }, // The form element's input value.
|
|
22
22
|
validators: { type: Array },
|
|
23
|
+
/** When `true`, skip blur validation for this element. When `false`, force blur validation even if `w-form` has `no-blur-validation`. When unset, inherit from the form. */
|
|
24
|
+
noBlurValidation: { type: Boolean },
|
|
23
25
|
isFocused: { default: false }, // Watched.
|
|
24
26
|
column: { default: false }, // Flex direction of the embedded component: column or row by default.
|
|
25
27
|
wrap: { default: false } // Flex-wrap if needed.
|
|
@@ -57,6 +59,13 @@ export default {
|
|
|
57
59
|
'w-form-el',
|
|
58
60
|
classes[this.Validation.isValid === null ? 2 : ~~this.Validation.isValid]
|
|
59
61
|
]
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Per-element `no-blur-validation` overrides the form when set; otherwise inherit `w-form`.
|
|
65
|
+
shouldSkipBlurValidation () {
|
|
66
|
+
if (this.noBlurValidation === true) return true
|
|
67
|
+
if (this.noBlurValidation === false) return false
|
|
68
|
+
return !!this.formProps.noBlurValidation
|
|
60
69
|
}
|
|
61
70
|
},
|
|
62
71
|
|
|
@@ -89,7 +98,7 @@ export default {
|
|
|
89
98
|
// When focusing, reset the hasJustReset flag so the input value is watched again.
|
|
90
99
|
if (val) this.hasJustReset = false
|
|
91
100
|
// On blur, Update the form element's validity.
|
|
92
|
-
else if (!this.
|
|
101
|
+
else if (!this.shouldSkipBlurValidation && this.validators && !this.readonly) {
|
|
93
102
|
this.$emit('update:valid', await this.validateElement(this))
|
|
94
103
|
}
|
|
95
104
|
}
|
|
@@ -49,7 +49,8 @@ export default {
|
|
|
49
49
|
formUnregister: this.unregister,
|
|
50
50
|
validateElement: this.validateElement,
|
|
51
51
|
// Give access to the form params (like disabled) to all the form components.
|
|
52
|
-
//
|
|
52
|
+
// Use the form instance (not `this.$props`): injected descendants must read reactive
|
|
53
|
+
// props (`no-blur-validation`, `no-keyup-validation`, etc.) through the instance proxy.
|
|
53
54
|
formProps: this.$props
|
|
54
55
|
}
|
|
55
56
|
},
|
|
@@ -77,7 +78,7 @@ export default {
|
|
|
77
78
|
},
|
|
78
79
|
|
|
79
80
|
unregister (formElement) {
|
|
80
|
-
this.formElements = this.formElements.filter(item => item
|
|
81
|
+
this.formElements = this.formElements.filter(item => item !== formElement)
|
|
81
82
|
},
|
|
82
83
|
|
|
83
84
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue, disabled: isDisabled, readonly: isReadonly, isFocused }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue, disabled: isDisabled, readonly: isReadonly, isFocused, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="$emit('update:modelValue', inputValue = '');$emit('input', '')"
|
|
8
8
|
:wrap="hasLabel && labelPosition !== 'inside'"
|
|
@@ -15,17 +15,17 @@ component(
|
|
|
15
15
|
template(v-if="labelPosition === 'left'")
|
|
16
16
|
label.w-input__label.w-input__label--left.w-form-el-shakable(
|
|
17
17
|
v-if="$slots.default || label"
|
|
18
|
-
:for="
|
|
18
|
+
:for="inputId"
|
|
19
19
|
:class="labelClasses")
|
|
20
20
|
slot {{ label }}
|
|
21
21
|
|
|
22
22
|
//- Input wrapper.
|
|
23
23
|
.w-input__input-wrap(:class="inputWrapClasses")
|
|
24
|
-
slot(name="icon-left" :input-id="
|
|
24
|
+
slot(name="icon-left" :input-id="inputId")
|
|
25
25
|
w-icon.w-input__icon.w-input__icon--inner-left(
|
|
26
26
|
v-if="innerIconLeft"
|
|
27
27
|
tag="label"
|
|
28
|
-
:for="
|
|
28
|
+
:for="inputId"
|
|
29
29
|
@click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
|
|
30
30
|
//- All types of input except file.
|
|
31
31
|
input.w-input__input(
|
|
@@ -35,7 +35,7 @@ component(
|
|
|
35
35
|
@input="onInput"
|
|
36
36
|
@focus="onFocus"
|
|
37
37
|
@blur="onBlur"
|
|
38
|
-
:id="
|
|
38
|
+
:id="inputId"
|
|
39
39
|
:type="type"
|
|
40
40
|
:name="inputName"
|
|
41
41
|
:placeholder="placeholder || null"
|
|
@@ -55,7 +55,7 @@ component(
|
|
|
55
55
|
template(v-else)
|
|
56
56
|
input(
|
|
57
57
|
ref="input"
|
|
58
|
-
:id="
|
|
58
|
+
:id="inputId"
|
|
59
59
|
type="file"
|
|
60
60
|
:name="name || null"
|
|
61
61
|
@focus="onFocus"
|
|
@@ -68,7 +68,7 @@ component(
|
|
|
68
68
|
transition-group.w-input__input.w-input__input--file(
|
|
69
69
|
tag="label"
|
|
70
70
|
name="fade"
|
|
71
|
-
:for="
|
|
71
|
+
:for="inputId")
|
|
72
72
|
span.w-input__no-file(v-if="!inputFiles.length && isFocused" key="no-file")
|
|
73
73
|
slot(name="no-file")
|
|
74
74
|
template(v-if="$slots['no-file'] === undefined") No file
|
|
@@ -83,11 +83,11 @@ component(
|
|
|
83
83
|
:class="labelClasses")
|
|
84
84
|
slot {{ label }}
|
|
85
85
|
|
|
86
|
-
slot(name="icon-right" :input-id="
|
|
86
|
+
slot(name="icon-right" :input-id="inputId")
|
|
87
87
|
w-icon.w-input__icon.w-input__icon--inner-right(
|
|
88
88
|
v-if="innerIconRight"
|
|
89
89
|
tag="label"
|
|
90
|
-
:for="
|
|
90
|
+
:for="inputId"
|
|
91
91
|
@click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
|
|
92
92
|
|
|
93
93
|
w-progress.fill-width(
|
|
@@ -97,7 +97,7 @@ component(
|
|
|
97
97
|
:model-value="showProgress ? (uploadInProgress || uploadComplete) && overallFilesProgress : loadingValue")
|
|
98
98
|
|
|
99
99
|
//- Files preview.
|
|
100
|
-
label.d-flex(v-if="type === 'file' && preview && inputFiles.length" :for="
|
|
100
|
+
label.d-flex(v-if="type === 'file' && preview && inputFiles.length" :for="inputId")
|
|
101
101
|
template(v-for="(file, i) in inputFiles")
|
|
102
102
|
i.w-icon.wi-spinner.w-icon--spin.size--sm.w-input__file-preview.primary(
|
|
103
103
|
v-if="file.progress < 100"
|
|
@@ -116,7 +116,7 @@ component(
|
|
|
116
116
|
template(v-if="labelPosition === 'right'")
|
|
117
117
|
label.w-input__label.w-input__label--right.w-form-el-shakable(
|
|
118
118
|
v-if="$slots.default || label"
|
|
119
|
-
:for="
|
|
119
|
+
:for="inputId"
|
|
120
120
|
:class="labelClasses")
|
|
121
121
|
slot {{ label }}
|
|
122
122
|
</template>
|
|
@@ -168,8 +168,8 @@ export default {
|
|
|
168
168
|
dark: { type: Boolean },
|
|
169
169
|
light: { type: Boolean },
|
|
170
170
|
inputClass: { type: String } // Additional classes for the input element.
|
|
171
|
-
// Props from mixin: name, disabled, readonly, required, tabindex, validators.
|
|
172
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
171
|
+
// Props from mixin: id, name, disabled, readonly, required, tabindex, validators.
|
|
172
|
+
// Computed from mixin: inputId, inputName, isDisabled & isReadonly.
|
|
173
173
|
},
|
|
174
174
|
|
|
175
175
|
emits: ['input', 'update:modelValue', 'focus', 'blur', 'click:inner-icon-left', 'click:inner-icon-right', 'update:overallProgress'],
|
|
@@ -43,9 +43,15 @@ ul.w-list(:class="classes")
|
|
|
43
43
|
</template>
|
|
44
44
|
|
|
45
45
|
<script>
|
|
46
|
+
import { useId } from 'vue'
|
|
47
|
+
|
|
46
48
|
export default {
|
|
47
49
|
name: 'w-list',
|
|
48
50
|
|
|
51
|
+
setup () {
|
|
52
|
+
return { _waveUiUseId: useId() }
|
|
53
|
+
},
|
|
54
|
+
|
|
49
55
|
props: {
|
|
50
56
|
items: { type: [Array, Number], required: true }, // All the possible options.
|
|
51
57
|
modelValue: {}, // v-model on selected item if any.
|
|
@@ -89,7 +95,8 @@ export default {
|
|
|
89
95
|
},
|
|
90
96
|
|
|
91
97
|
listId () {
|
|
92
|
-
|
|
98
|
+
if (!this.addIds) return null
|
|
99
|
+
return typeof this.addIds === 'string' ? this.addIds : `w-list--${this._waveUiUseId}`
|
|
93
100
|
},
|
|
94
101
|
|
|
95
102
|
selectedItems () {
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister && !wRadios ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue, disabled: isDisabled, readonly: isReadonly }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue, disabled: isDisabled, readonly: isReadonly, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="$emit('update:modelValue', inputValue = null);$emit('input', null)"
|
|
8
8
|
:class="classes")
|
|
9
9
|
input(
|
|
10
10
|
ref="input"
|
|
11
|
-
:id="
|
|
11
|
+
:id="inputId"
|
|
12
12
|
type="radio"
|
|
13
13
|
:name="inputName"
|
|
14
14
|
:checked="inputValue || null"
|
|
@@ -22,12 +22,12 @@ component(
|
|
|
22
22
|
template(v-if="hasLabel && labelOnLeft")
|
|
23
23
|
label.w-radio__label.w-form-el-shakable.pr2(
|
|
24
24
|
v-if="$slots.default"
|
|
25
|
-
:for="
|
|
25
|
+
:for="inputId"
|
|
26
26
|
:class="labelClasses")
|
|
27
27
|
slot {{ label }}
|
|
28
28
|
label.w-radio__label.w-form-el-shakable.pr2(
|
|
29
29
|
v-else-if="label"
|
|
30
|
-
:for="
|
|
30
|
+
:for="inputId"
|
|
31
31
|
:class="labelClasses"
|
|
32
32
|
v-html="label")
|
|
33
33
|
.w-radio__input(
|
|
@@ -36,12 +36,12 @@ component(
|
|
|
36
36
|
template(v-if="hasLabel && !labelOnLeft")
|
|
37
37
|
label.w-radio__label.w-form-el-shakable.pl2(
|
|
38
38
|
v-if="$slots.default"
|
|
39
|
-
:for="
|
|
39
|
+
:for="inputId"
|
|
40
40
|
:class="labelClasses")
|
|
41
41
|
slot {{ label }}
|
|
42
42
|
label.w-radio__label.w-form-el-shakable.pl2(
|
|
43
43
|
v-else-if="label"
|
|
44
|
-
:for="
|
|
44
|
+
:for="inputId"
|
|
45
45
|
:class="labelClasses"
|
|
46
46
|
v-html="label")
|
|
47
47
|
</template>
|
|
@@ -66,8 +66,8 @@ export default {
|
|
|
66
66
|
noRipple: { type: Boolean },
|
|
67
67
|
dark: { type: Boolean },
|
|
68
68
|
light: { type: Boolean }
|
|
69
|
-
// Props from mixin: name, disabled, readonly, required, tabindex, validators.
|
|
70
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
69
|
+
// Props from mixin: id, name, disabled, readonly, required, tabindex, validators.
|
|
70
|
+
// Computed from mixin: inputId, inputName, isDisabled & isReadonly.
|
|
71
71
|
},
|
|
72
72
|
|
|
73
73
|
emits: ['input', 'update:modelValue', 'focus'],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue, disabled: isDisabled }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue, disabled: isDisabled, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="$emit('update:modelValue', inputValue = null);$emit('input', null)"
|
|
8
8
|
:column="!inline"
|
|
@@ -46,7 +46,7 @@ export default {
|
|
|
46
46
|
inline: { type: Boolean },
|
|
47
47
|
color: { type: String, default: 'primary' },
|
|
48
48
|
labelColor: { type: String, default: 'primary' }
|
|
49
|
-
// Props from mixin: name, disabled, readonly, required, validators.
|
|
49
|
+
// Props from mixin: id, name, disabled, readonly, required, validators.
|
|
50
50
|
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
51
51
|
},
|
|
52
52
|
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: rating, disabled: isDisabled, readonly: isReadonly }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: rating, disabled: isDisabled, readonly: isReadonly, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="$emit('update:modelValue', rating = null);$emit('input', null)"
|
|
8
8
|
:class="classes")
|
|
9
|
-
input(:id="
|
|
9
|
+
input(:id="inputId" :name="inputName" type="hidden" :value="rating")
|
|
10
10
|
template(v-for="i in max" :key="i")
|
|
11
11
|
slot(v-if="$slots.item" name="item" :index="i + 1")
|
|
12
12
|
button.w-rating__button(
|
|
@@ -49,8 +49,8 @@ export default {
|
|
|
49
49
|
noRipple: { type: Boolean },
|
|
50
50
|
dark: { type: Boolean },
|
|
51
51
|
light: { type: Boolean }
|
|
52
|
-
// Props from mixin: name, disabled, readonly, required, validators.
|
|
53
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
52
|
+
// Props from mixin: id, name, disabled, readonly, required, validators.
|
|
53
|
+
// Computed from mixin: inputId, inputName, isDisabled & isReadonly.
|
|
54
54
|
},
|
|
55
55
|
|
|
56
56
|
emits: ['input', 'update:modelValue', 'focus', 'blur'],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: selectionString, disabled: isDisabled, readonly: isReadonly, isFocused }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: selectionString, disabled: isDisabled, readonly: isReadonly, isFocused, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="onReset"
|
|
8
8
|
:wrap="hasLabel && labelPosition !== 'inside'"
|
|
@@ -31,8 +31,8 @@ component(
|
|
|
31
31
|
role="button"
|
|
32
32
|
aria-haspopup="listbox"
|
|
33
33
|
:aria-expanded="showMenu ? 'true' : 'false'"
|
|
34
|
-
:aria-owns="
|
|
35
|
-
:aria-activedescendant="
|
|
34
|
+
:aria-owns="selectListId"
|
|
35
|
+
:aria-activedescendant="`${selectListId}_item-1`"
|
|
36
36
|
:class="inputWrapClasses")
|
|
37
37
|
slot(name="icon-left")
|
|
38
38
|
w-icon.w-select__icon.w-select__icon--inner-left(
|
|
@@ -79,7 +79,7 @@ component(
|
|
|
79
79
|
:multiple="multiple"
|
|
80
80
|
arrows-navigation
|
|
81
81
|
return-object
|
|
82
|
-
:add-ids="
|
|
82
|
+
:add-ids="selectListId"
|
|
83
83
|
:no-unselect="noUnselect"
|
|
84
84
|
:selection-color="selectionColor"
|
|
85
85
|
:item-color-key="itemColorKey"
|
|
@@ -146,8 +146,8 @@ export default {
|
|
|
146
146
|
dark: { type: Boolean },
|
|
147
147
|
light: { type: Boolean },
|
|
148
148
|
fitToContent: { type: Boolean }
|
|
149
|
-
// Props from mixin: name, disabled, readonly, required, tabindex, validators.
|
|
150
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
149
|
+
// Props from mixin: id, name, disabled, readonly, required, tabindex, validators.
|
|
150
|
+
// Computed from mixin: inputId, selectListId, inputName, isDisabled & isReadonly.
|
|
151
151
|
},
|
|
152
152
|
|
|
153
153
|
emits: ['input', 'update:modelValue', 'focus', 'blur', 'item-click', 'item-select', 'click:inner-icon-left', 'click:inner-icon-right'],
|
|
@@ -166,6 +166,11 @@ export default {
|
|
|
166
166
|
}),
|
|
167
167
|
|
|
168
168
|
computed: {
|
|
169
|
+
/** Prefix for w-list item ids (`id_item-N`) and ARIA listbox linkage; stable with SSR. */
|
|
170
|
+
selectListId () {
|
|
171
|
+
return this.id ? `${this.id}__listbox` : `w-select-menu--${this._waveUiUseId}`
|
|
172
|
+
},
|
|
173
|
+
|
|
169
174
|
// Check all the items and add a `value` if missing, containing either: value, label or index
|
|
170
175
|
// in this order.
|
|
171
176
|
selectItems () {
|
|
@@ -394,7 +399,7 @@ export default {
|
|
|
394
399
|
setTimeout(() => {
|
|
395
400
|
const itemIndex = this.inputValue.length ? this.inputValue[0].index : 0 // Real index starts at 0.
|
|
396
401
|
// User visible index starts at 1.
|
|
397
|
-
|
|
402
|
+
document.getElementById(`${this.selectListId}_item-${itemIndex + 1}`)?.focus()
|
|
398
403
|
}, 100)
|
|
399
404
|
},
|
|
400
405
|
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: rangeValueScaled, disabled: isDisabled, readonly: isReadonly }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: rangeValueScaled, disabled: isDisabled, readonly: isReadonly, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@reset="rangeValuePercent = 0;updateRangeValueScaled()"
|
|
8
8
|
:wrap="formRegister || null"
|
|
9
9
|
:class="wrapperClasses")
|
|
10
10
|
label.w-slider__label.w-slider__label--left.w-form-el-shakable(
|
|
11
11
|
v-if="$slots['label-left']"
|
|
12
|
-
:for="
|
|
12
|
+
:for="thumbId"
|
|
13
13
|
:class="labelClasses")
|
|
14
14
|
slot(name="label-left")
|
|
15
15
|
label.w-slider__label.w-slider__label--left.w-form-el-shakable(
|
|
16
16
|
v-else-if="labelLeft"
|
|
17
|
-
:for="
|
|
17
|
+
:for="thumbId"
|
|
18
18
|
:class="labelClasses"
|
|
19
19
|
v-html="labelLeft")
|
|
20
20
|
.w-slider__track-wrap
|
|
@@ -34,7 +34,7 @@ component(
|
|
|
34
34
|
.w-slider__thumb(:style="thumbStyles")
|
|
35
35
|
button.w-slider__thumb-button(
|
|
36
36
|
ref="thumb"
|
|
37
|
-
:id="
|
|
37
|
+
:id="thumbId"
|
|
38
38
|
:class="[color]"
|
|
39
39
|
:name="inputName"
|
|
40
40
|
:model-value="rangeValueScaled"
|
|
@@ -48,7 +48,7 @@ component(
|
|
|
48
48
|
@click.prevent)
|
|
49
49
|
label.w-slider__thumb-label(
|
|
50
50
|
v-if="thumbLabel"
|
|
51
|
-
:for="
|
|
51
|
+
:for="thumbId"
|
|
52
52
|
:class="thumbClasses")
|
|
53
53
|
div(v-if="thumbLabel === 'droplet'")
|
|
54
54
|
slot(name="label" :value="rangeValueScaled") {{ ~~rangeValueScaled }}
|
|
@@ -67,12 +67,12 @@ component(
|
|
|
67
67
|
style="left: 100%") {{ this.maxVal }}
|
|
68
68
|
label.w-slider__label.w-slider__label--right.w-form-el-shakable(
|
|
69
69
|
v-if="$slots['label-right']"
|
|
70
|
-
:for="
|
|
70
|
+
:for="thumbId"
|
|
71
71
|
:class="labelClasses")
|
|
72
72
|
slot(name="label-right")
|
|
73
73
|
label.w-slider__label.w-slider__label--right.w-form-el-shakable(
|
|
74
74
|
v-else-if="labelRight"
|
|
75
|
-
:for="
|
|
75
|
+
:for="thumbId"
|
|
76
76
|
:class="labelClasses"
|
|
77
77
|
v-html="labelRight")
|
|
78
78
|
</template>
|
|
@@ -101,8 +101,8 @@ export default {
|
|
|
101
101
|
labelRight: { type: String },
|
|
102
102
|
dark: { type: Boolean },
|
|
103
103
|
light: { type: Boolean }
|
|
104
|
-
// Props from mixin: name, disabled, readonly, required, validators.
|
|
105
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
104
|
+
// Props from mixin: id, name, disabled, readonly, required, validators.
|
|
105
|
+
// Computed from mixin: inputId, thumbId, inputName, isDisabled & isReadonly.
|
|
106
106
|
},
|
|
107
107
|
|
|
108
108
|
emits: ['input', 'update:modelValue', 'focus'],
|
|
@@ -119,6 +119,11 @@ export default {
|
|
|
119
119
|
}),
|
|
120
120
|
|
|
121
121
|
computed: {
|
|
122
|
+
/** DOM id for the thumb control and related labels (distinct from `inputId` on `w-slider`). */
|
|
123
|
+
thumbId () {
|
|
124
|
+
return this.id ? `${this.id}__thumb` : `button--${this._waveUiUseId}`
|
|
125
|
+
},
|
|
126
|
+
|
|
122
127
|
minVal () {
|
|
123
128
|
return parseFloat(this.min)
|
|
124
129
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
component(
|
|
3
3
|
ref="formEl"
|
|
4
4
|
:is="formRegister ? 'w-form-element' : 'div'"
|
|
5
|
-
v-bind="formRegister && { validators, inputValue: isOn, disabled: isDisabled, readonly: isReadonly }"
|
|
5
|
+
v-bind="formRegister && { validators, inputValue: isOn, disabled: isDisabled, readonly: isReadonly, noBlurValidation }"
|
|
6
6
|
v-model:valid="valid"
|
|
7
7
|
@mouseenter="$emit('mouseenter', $event)"
|
|
8
8
|
@mouseleave="$emit('mouseleave', $event)"
|
|
@@ -11,7 +11,7 @@ component(
|
|
|
11
11
|
:style="$attrs.style")
|
|
12
12
|
input(
|
|
13
13
|
ref="input"
|
|
14
|
-
:id="
|
|
14
|
+
:id="inputId"
|
|
15
15
|
type="checkbox"
|
|
16
16
|
:name="inputName"
|
|
17
17
|
:checked="isOn"
|
|
@@ -29,7 +29,7 @@ component(
|
|
|
29
29
|
template(v-if="hasLabel && labelOnLeft")
|
|
30
30
|
label.w-switch__label.w-switch__label--left.w-form-el-shakable(
|
|
31
31
|
v-if="$slots.default || label"
|
|
32
|
-
:for="
|
|
32
|
+
:for="inputId"
|
|
33
33
|
:class="labelClasses")
|
|
34
34
|
slot {{ label }}
|
|
35
35
|
.w-switch__input(
|
|
@@ -47,7 +47,7 @@ component(
|
|
|
47
47
|
template(v-if="hasLabel && !labelOnLeft")
|
|
48
48
|
label.w-switch__label.w-switch__label--right.w-form-el-shakable(
|
|
49
49
|
v-if="$slots.default || label"
|
|
50
|
-
:for="
|
|
50
|
+
:for="inputId"
|
|
51
51
|
:class="labelClasses")
|
|
52
52
|
slot {{ label }}
|
|
53
53
|
</template>
|
|
@@ -71,8 +71,8 @@ export default {
|
|
|
71
71
|
loading: { type: [Boolean, Number], default: false },
|
|
72
72
|
dark: { type: Boolean },
|
|
73
73
|
light: { type: Boolean }
|
|
74
|
-
// Props from mixin: name, disabled, readonly, required, tabindex, validators.
|
|
75
|
-
// Computed from mixin: inputName, isDisabled & isReadonly.
|
|
74
|
+
// Props from mixin: id, name, disabled, readonly, required, tabindex, validators.
|
|
75
|
+
// Computed from mixin: inputId, inputName, isDisabled & isReadonly.
|
|
76
76
|
},
|
|
77
77
|
|
|
78
78
|
emits: ['input', 'update:modelValue', 'focus', 'blur', 'mouseenter', 'mouseleave'],
|
|
@@ -71,14 +71,17 @@
|
|
|
71
71
|
</template>
|
|
72
72
|
|
|
73
73
|
<script>
|
|
74
|
+
import { useId } from 'vue'
|
|
74
75
|
import { objectifyClasses } from '../../utils/index'
|
|
75
76
|
import TabContent from './tab-content.vue'
|
|
76
77
|
|
|
77
|
-
let uid = 0
|
|
78
|
-
|
|
79
78
|
export default {
|
|
80
79
|
name: 'w-tabs',
|
|
81
80
|
|
|
81
|
+
setup () {
|
|
82
|
+
return { _tabsStableId: useId() }
|
|
83
|
+
},
|
|
84
|
+
|
|
82
85
|
props: {
|
|
83
86
|
modelValue: { type: [Number, String] },
|
|
84
87
|
color: { type: String },
|
|
@@ -180,7 +183,7 @@ export default {
|
|
|
180
183
|
addTab (item) {
|
|
181
184
|
// If there is no unique ID provided, inject one in each tab.
|
|
182
185
|
// This will cause a single other update from watching the tabs items and stop there.
|
|
183
|
-
if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid =
|
|
186
|
+
if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid = `${this._tabsStableId}-${this.tabs.length}`
|
|
184
187
|
|
|
185
188
|
this.tabs.push({
|
|
186
189
|
_uid: item[this.itemIdKey] ?? item._uid,
|
|
@@ -197,7 +200,7 @@ export default {
|
|
|
197
200
|
this.tabs = items.map((item, _index) => {
|
|
198
201
|
// If there is no unique ID provided, inject one in each tab.
|
|
199
202
|
// This will cause a single other update from watching the tabs items and stop there.
|
|
200
|
-
if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid =
|
|
203
|
+
if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid = `${this._tabsStableId}-${_index}`
|
|
201
204
|
|
|
202
205
|
return {
|
|
203
206
|
...item,
|