Accessibility for Rating
parent
4b17571644
commit
d8ec9abd14
|
@ -66,7 +66,10 @@ const defaultOptions = {
|
|||
aria: {
|
||||
trueLabel: 'True',
|
||||
falseLabel: 'False',
|
||||
nullLabel: 'Not Selected'
|
||||
nullLabel: 'Not Selected',
|
||||
star: 'star',
|
||||
stars: 'stars',
|
||||
noneStars: 'No Rating'
|
||||
}
|
||||
},
|
||||
filterMatchModeOptions: {
|
||||
|
|
|
@ -16,6 +16,10 @@ export interface RatingProps {
|
|||
* Value of the rating.
|
||||
*/
|
||||
modelValue?: number | undefined;
|
||||
/**
|
||||
* Name of the element.
|
||||
*/
|
||||
name?: string | undefined;
|
||||
/**
|
||||
* When present, it specifies that the element should be disabled.
|
||||
*/
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
<template>
|
||||
<div :class="containerClass">
|
||||
<span class="p-rating-icon p-rating-cancel pi pi-ban" :tabindex="focusIndex" v-if="cancel" @click="onCancelClick"></span>
|
||||
<span :key="i" v-for="i in stars" @click="onStarClick($event,i)" :tabindex="focusIndex" @keydown.enter.prevent="onStarClick($event,i)"
|
||||
:class="['p-rating-icon', {'pi pi-star': (i > modelValue), 'pi pi-star-fill': (i <= modelValue)}]"></span>
|
||||
<span class="p-hidden-accessible" v-if="cancel">
|
||||
<label :for="labelFor(0)">{{labelText(0)}}</label>
|
||||
<input type="radio" :id="labelFor(0)" value="0" :name="name" :checked="modelValue === 0" :disabled="disabled" :readonly="readonly" @focus="onFocus($event, 0)" @blur="onBlur" @keydown="onKeyDown($event, 0)">
|
||||
</span>
|
||||
<span :class="['p-rating-icon p-rating-cancel pi pi-ban', {'p-focus': focusIndex === 0}]" v-if="cancel" @click="onCancelClick" @keydown="onKeyDown"></span>
|
||||
|
||||
<template :key="i" v-for="i in stars">
|
||||
<span class="p-hidden-accessible">
|
||||
<label :for="labelFor(i)">{{labelText(i)}}</label>
|
||||
<input type="radio" :id="labelFor(i)" :value="i" :name="name" :checked="modelValue === i" :disabled="disabled" :readonly="readonly" @focus="onFocus($event, i)" @blur="onBlur" @keydown="onKeyDown($event,i)">
|
||||
</span>
|
||||
<span :class="['p-rating-icon', {'pi pi-star': (i > modelValue), 'pi pi-star-fill': (i <= modelValue), 'p-focus': i === focusIndex}]" @click="onStarClick($event,i)"></span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Rating',
|
||||
emits: ['update:modelValue', 'change'],
|
||||
emits: ['update:modelValue', 'change', 'focus', 'blur'],
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
|
@ -32,12 +46,46 @@ export default {
|
|||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
focusIndex: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onStarClick(event, value) {
|
||||
if (!this.readonly && !this.disabled) {
|
||||
this.updateModel(event, value);
|
||||
this.focusIndex = value;
|
||||
}
|
||||
},
|
||||
onKeyDown(event, value) {
|
||||
if (event.code === 'Space') {
|
||||
this.updateModel(event, value);
|
||||
}
|
||||
if (event.code === 'Tab') {
|
||||
this.focusIndex = null;
|
||||
}
|
||||
},
|
||||
onFocus(event, index) {
|
||||
if (!this.readonly) {
|
||||
if (this.modelValue === null && this.focusIndex === null) {
|
||||
this.cancel ? this.focusIndex = 0 : this.focusIndex = 1;
|
||||
}
|
||||
else if (this.modelValue !== null && this.focusIndex === null) {
|
||||
this.focusIndex = this.modelValue;
|
||||
this.updateModel(event, this.modelValue);
|
||||
}
|
||||
else {
|
||||
this.focusIndex = index;
|
||||
this.updateModel(event, index);
|
||||
}
|
||||
|
||||
this.$emit('focus', event);
|
||||
}
|
||||
},
|
||||
onBlur(event) {
|
||||
this.$emit('blur', event);
|
||||
},
|
||||
onCancelClick(event) {
|
||||
if (!this.readonly && !this.disabled) {
|
||||
this.updateModel(event, null);
|
||||
|
@ -49,6 +97,13 @@ export default {
|
|||
originalEvent: event,
|
||||
value: value
|
||||
});
|
||||
},
|
||||
labelFor(index) {
|
||||
return this.name + '_' + index;
|
||||
},
|
||||
labelText(index) {
|
||||
return index === 0 ? this.$primevue.config.locale.aria.noneStars : index === 1
|
||||
? index + ' ' + this.$primevue.config.locale.aria.star : index + ' ' + this.$primevue.config.locale.aria.stars;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -60,9 +115,6 @@ export default {
|
|||
'p-disabled': this.disabled
|
||||
}
|
||||
];
|
||||
},
|
||||
focusIndex() {
|
||||
return (this.disabled || this.readonly) ? null : '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,4 +128,11 @@ export default {
|
|||
.p-rating.p-rating-readonly .p-rating-icon {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.p-rating:not(.p-disabled) .p-rating-icon.p-focus {
|
||||
outline: 0 none;
|
||||
outline-offset: 0;
|
||||
box-shadow: 0 0 0 0.2rem #BFDBFE;
|
||||
border-color: #3B82F6;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
<div class="content-section implementation">
|
||||
<div class="card">
|
||||
<h5>Basic {{val1}}</h5>
|
||||
<Rating v-model="val1" />
|
||||
<Rating v-model="val1" name="basic" />
|
||||
|
||||
<h5>Without Cancel</h5>
|
||||
<Rating v-model="val2" :cancel="false" />
|
||||
<Rating v-model="val2" :cancel="false" name="cancel" />
|
||||
|
||||
<h5>ReadOnly</h5>
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" />
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" name="readonly" />
|
||||
|
||||
<h5>Disabled</h5>
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" />
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" name="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -53,6 +53,12 @@ import Rating from 'primevue/rating';
|
|||
<td>null</td>
|
||||
<td>Value of the rating.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name</td>
|
||||
<td>string</td>
|
||||
<td>null</td>
|
||||
<td>Name of the element.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>disabled</td>
|
||||
<td>boolean</td>
|
||||
|
@ -133,6 +139,53 @@ import Rating from 'primevue/rating';
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<h5>Accessibility</h5>
|
||||
<DevelopmentSection>
|
||||
<h6>Screen Reader</h6>
|
||||
<p>Rating component internally uses radio buttons that are only visible to screen readers. The value to read for item is retrieved from the <Link href="/locale">locale</Link> API via <i>star</i> and <i>stars</i> of the <i>aria</i> property.</p>
|
||||
|
||||
<h6>Keyboard Support</h6>
|
||||
<p>Keyboard interaction is derived from the native browser handling of radio buttons in a group.</p>
|
||||
<div class="doc-tablewrapper">
|
||||
<table class="doc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Function</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><i>tab</i></td>
|
||||
<td>Moves focus to the star representing the value, if there is none then first star receives the focus.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="inline-flex flex-column">
|
||||
<i class="mb-1">left arrow</i>
|
||||
<i>up arrow</i>
|
||||
</span>
|
||||
</td>
|
||||
<td>Moves focus to the previous star, if there is none then last radio button receives the focus.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="inline-flex flex-column">
|
||||
<i class="mb-1">right arrow</i>
|
||||
<i>down arrow</i>
|
||||
</span>
|
||||
</td>
|
||||
<td>Moves focus to the next star, if there is none then first star receives the focus.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i>space</i></td>
|
||||
<td>If the focused star does not represent the value, changes the value to the star value.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</DevelopmentSection>
|
||||
|
||||
<h5>Dependencies</h5>
|
||||
<p>None.</p>
|
||||
</AppDoc>
|
||||
|
@ -149,16 +202,16 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<h5>Basic {{val1}}</h5>
|
||||
<Rating v-model="val1" />
|
||||
<Rating v-model="val1" name="basic" />
|
||||
|
||||
<h5>Without Cancel</h5>
|
||||
<Rating v-model="val2" :cancel="false" />
|
||||
<Rating v-model="val2" :cancel="false" name="cancel" />
|
||||
|
||||
<h5>ReadOnly</h5>
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" />
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" name="readonly" />
|
||||
|
||||
<h5>Disabled</h5>
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" />
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" name="disabled" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -180,16 +233,16 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<h5>Basic {{val1}}</h5>
|
||||
<Rating v-model="val1" />
|
||||
<Rating v-model="val1" name="basic" />
|
||||
|
||||
<h5>Without Cancel</h5>
|
||||
<Rating v-model="val2" :cancel="false" />
|
||||
<Rating v-model="val2" :cancel="false" name="cancel" />
|
||||
|
||||
<h5>ReadOnly</h5>
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" />
|
||||
<Rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" name="readonly" />
|
||||
|
||||
<h5>Disabled</h5>
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" />
|
||||
<Rating :modelValue="8" :disabled="true" :stars="10" name="disabled" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -212,16 +265,16 @@ export default {
|
|||
imports: `<script src="https://unpkg.com/primevue@^3/rating/rating.min.js"><\\/script>`,
|
||||
content: `<div id="app">
|
||||
<h5>Basic {{val1}}</h5>
|
||||
<p-rating v-model="val1"></p-rating>
|
||||
<p-rating v-model="val1" name="basic"></p-rating>
|
||||
|
||||
<h5>Without Cancel</h5>
|
||||
<p-rating v-model="val2" :cancel="false"></p-rating>
|
||||
<p-rating v-model="val2" :cancel="false" name="cancel"></p-rating>
|
||||
|
||||
<h5>ReadOnly</h5>
|
||||
<p-rating :model-value="5" :readonly="true" :stars="10" :cancel="false"></p-rating>
|
||||
<p-rating :modelValue="5" :readonly="true" :stars="10" :cancel="false" name="readonly"></p-rating>
|
||||
|
||||
<h5>Disabled</h5>
|
||||
<p-rating :model-value="8" :disabled="true" :stars="10"></p-rating>
|
||||
<p-rating :modelValue="8" :disabled="true" :stars="10" name="disabled"></p-rating>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
|
|
Loading…
Reference in New Issue