Skip to content

Commit

Permalink
feat(rating-stars): improve prop naming (#558)
Browse files Browse the repository at this point in the history
* feat: new props and testing

* feat: storybook

* fix: snapshots; formatting

* refactor: remove reflect from deprecated props

* feat: status note for deprecated; deprecated logic from attribute to prop
  • Loading branch information
ChrisPaj authored Sep 8, 2021
1 parent d87d6c3 commit 3ceb6c1
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,91 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`RatingStars snapshots deprecated overwrite actual props 1`] = `
<scale-rating-stars max="12" max-rating="12" rating="0" size="small" star-size="small">
<mock:shadow-root>
<div part="container">
<div aria-labeledby="scale-rating-star-5-label" aria-orientation="horizontal" aria-valuetext="0 out of 12 stars" part="wrapper" role="figure" tabindex="-1">
<input aria-orientation="horizontal" aria-valuemax="12" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0 out of 12 stars" id="scale-rating-star-5" max="13" min="0" part="range-slider" step="1" type="range" value="0">
<div data-value="1" part="star" style="z-index: 5;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="2" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="3" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="4" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="5" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="6" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="7" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="8" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="9" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="10" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="11" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
<div data-value="12" part="star" style="z-index: auto;">
<scale-icon-action-favorite part="placeholder-star" size="16"></scale-icon-action-favorite>
<div class="icon-clip">
<scale-icon-action-favorite part="selected-star" selected="" size="16"></scale-icon-action-favorite>
</div>
</div>
</div>
</div>
</mock:shadow-root>
</scale-rating-stars>
`;
exports[`RatingStars snapshots rating 2 1`] = `
<scale-rating-stars max-rating="5" min-rating="0" rating="2" star-size="large">
<scale-rating-stars max="5" rating="2" size="large">
<mock:shadow-root>
<div part="container">
<div aria-labeledby="scale-rating-star-1-label" aria-orientation="horizontal" aria-valuetext="2 out of 5 stars" part="wrapper" role="figure" tabindex="-1">
Expand Down Expand Up @@ -43,7 +127,7 @@ exports[`RatingStars snapshots rating 2 1`] = `
`;
exports[`RatingStars snapshots rating 2, maxRating 7 1`] = `
<scale-rating-stars max-rating="7" min-rating="0" rating="2" star-size="large">
<scale-rating-stars max="7" max-rating="7" rating="2" size="large">
<mock:shadow-root>
<div part="container">
<div aria-labeledby="scale-rating-star-3-label" aria-orientation="horizontal" aria-valuetext="2 out of 7 stars" part="wrapper" role="figure" tabindex="-1">
Expand Down Expand Up @@ -97,7 +181,7 @@ exports[`RatingStars snapshots rating 2, maxRating 7 1`] = `
`;
exports[`RatingStars snapshots rating 3, disabled 1`] = `
<scale-rating-stars disabled="" max-rating="5" min-rating="0" rating="0" star-size="large">
<scale-rating-stars disabled="" max="5" rating="0" size="large">
<mock:shadow-root>
<div part="container">
<div aria-labeledby="scale-rating-star-4-label" aria-orientation="horizontal" aria-valuetext="0 out of 5 stars" part="wrapper" role="figure" tabindex="-1">
Expand Down Expand Up @@ -139,7 +223,7 @@ exports[`RatingStars snapshots rating 3, disabled 1`] = `
`;
exports[`RatingStars snapshots rating 3, minRating 1 1`] = `
<scale-rating-stars max-rating="5" min-rating="1" rating="3" star-size="large">
<scale-rating-stars max="5" min-rating="1" rating="3" size="large">
<mock:shadow-root>
<div part="container">
<div aria-labeledby="scale-rating-star-2-label" aria-orientation="horizontal" aria-valuetext="3 out of 5 stars" part="wrapper" role="figure" tabindex="-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,24 @@ describe('RatingStars', () => {

it('check non default props', async () => {
page.root.maxRating = 7;
page.root.minRating = 1;
page.root.max = 7;
page.root.minRating = 0;
page.root.rating = 4;
page.root.starSize = 'small';
page.root.size = 'small';
page.root.disabled = true;
page.root.ariaLabelTranslation = '$value aus $maxValue Sternen';
page.root.ariaLabelTranslation = '$value aus $max Sternen';
page.root.label = 'Rating Label';
await page.waitForChanges();
expect(page.rootInstance.maxRating).toBe(7);
expect(page.rootInstance.minRating).toBe(1);
expect(page.rootInstance.max).toBe(7);
expect(page.rootInstance.minRating).toBe(0);
expect(page.rootInstance.rating).toBe(4);
expect(page.rootInstance.starSize).toBe('small');
expect(page.rootInstance.size).toBe('small');
expect(page.rootInstance.disabled).toBe(true);
expect(page.rootInstance.ariaLabelTranslation).toBe(
'$value aus $maxValue Sternen'
'$value aus $max Sternen'
);
expect(page.rootInstance.label).toBe('Rating Label');
});
Expand Down Expand Up @@ -76,6 +80,15 @@ describe('RatingStars', () => {
});
expect(page.root).toMatchSnapshot();
});
it('deprecated overwrite actual props', async () => {
page = await newSpecPage({
components: [RatingStars],
html: `<scale-rating-stars max-rating="12" star-size="small"></scale-rating-stars>`,
});
expect(page.root).toMatchSnapshot();
expect(page.rootInstance.max).toBe(12);
expect(page.rootInstance.size).toBe('small');
});
});

describe('emitter', () => {
Expand Down
60 changes: 46 additions & 14 deletions packages/components/src/components/rating-stars/rating-stars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
EventEmitter,
} from '@stencil/core';
import { emitEvent } from '../../utils/utils';
import statusNote from '../../utils/status-note';

export interface StarInterface extends HTMLDivElement {
dataset: {
Expand All @@ -42,20 +43,24 @@ export class RatingStars {

ratingStarId = `scale-rating-star-${ratingStarCount++}`;

/** The lower limit of the rating. In cases where */
@Prop({ reflect: true }) starSize: 'small' | 'large' = 'large';
/** The lower limit of the rating. In cases where */
@Prop({ reflect: true }) minRating = 0;
/** Deprecated; size should be used instead of starSize */
@Prop() starSize: 'small' | 'large' = 'large';
/** size of the stars */
@Prop({ reflect: true, mutable: true }) size: 'small' | 'large' = 'large';
/** Deprecated; The lower limit of the rating */
@Prop() minRating = 0;
/** Deprecated; max should be used instead of maxRating */
@Prop() maxRating = 5;
/** The upper limit of the rating */
@Prop({ reflect: true }) maxRating = 5;
@Prop({ reflect: true, mutable: true }) max = 5;
/** Represents the current value of the rating */
@Prop({ mutable: true, reflect: true }) rating = 0;
/** makes the rating non-interactive (but still accessible) */
@Prop({ reflect: true }) readonly = false;
/** disables input */
@Prop({ reflect: true }) disabled = false;
/** a11y text for getting meaningful value. `$rating` and `$maxRating` are template variables and will be replaces by their corresponding properties. */
@Prop() ariaLabelTranslation = '$rating out of $maxRating stars';
/** a11y text for getting meaningful value. `$rating` and `$max` (deprecated `$maxRating`) are template variables and will be replaces by their corresponding properties. */
@Prop() ariaLabelTranslation = '$rating out of $max stars';
/** (optional) rating label */
@Prop({ reflect: true }) label?: string;

Expand All @@ -64,11 +69,38 @@ export class RatingStars {
/** @deprecated in v3 in favor of kebab-case event names */
@Event({ eventName: 'scaleChange' }) scaleChangeLegacy: EventEmitter;

componentWillRender() {
// make sure the deprecated props overwrite the actual ones if used
// and show status note deprecated
if (this.maxRating !== 5) {
this.max = this.maxRating;
statusNote({
tag: 'deprecated',
message:
'Property "maxRating" is deprecated. Please use the "max" property!',
type: 'warn',
source: this.host,
});
}
if (this.starSize !== 'large') {
this.size = this.starSize;
statusNote({
tag: 'deprecated',
message:
'Property "starSize" is deprecated. Please use the "size" property!',
type: 'warn',
source: this.host,
});
}
}

// constructs the aria message for the current rating
getRatingText() {
const filledText = this.ariaLabelTranslation
.replace(/\$rating/g, `${this.rating}`)
.replace(/\$maxRating/g, `${this.maxRating}`);
// TODO: remove when `maxRating` is also being removed
.replace(/\$maxRating/g, `${this.max}`)
.replace(/\$max/g, `${this.max}`);
return filledText;
}

Expand All @@ -81,8 +113,8 @@ export class RatingStars {
input.value = this.minRating.toString();
break;

case value > this.maxRating:
input.value = this.maxRating.toString();
case value > this.max:
input.value = this.max.toString();
break;
}

Expand All @@ -108,7 +140,7 @@ export class RatingStars {
};

renderStar(index: number, selected = false, rating: number) {
const size = sizes[this.starSize];
const size = sizes[this.size];
const isWholeNumber = rating % 1 === 0;
const isLastNumber = Math.ceil(rating) === index;

Expand Down Expand Up @@ -137,7 +169,7 @@ export class RatingStars {
renderRating() {
const stars = [];
const roundedRating = Math.ceil(this.rating);
const max = this.maxRating;
const max = this.max;

for (let index = 1; index <= max; index++) {
const isSelected = roundedRating >= index;
Expand Down Expand Up @@ -175,12 +207,12 @@ export class RatingStars {
type="range"
id={this.ratingStarId}
min={0}
max={this.maxRating + 1}
max={this.max + 1}
value={this.rating}
step="1"
aria-orientation="horizontal"
aria-valuemin={this.minRating}
aria-valuemax={this.maxRating}
aria-valuemax={this.max}
aria-valuenow={this.rating}
aria-valuetext={this.getRatingText()}
onInput={!this.readonly && this.handleInput}
Expand Down
22 changes: 12 additions & 10 deletions packages/components/src/components/rating-stars/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ----------------------------------- |
| `ariaLabelTranslation` | `aria-label-translation` | a11y text for getting meaningful value. `$rating` and `$maxRating` are template variables and will be replaces by their corresponding properties. | `string` | `'$rating out of $maxRating stars'` |
| `disabled` | `disabled` | disables input | `boolean` | `false` |
| `label` | `label` | (optional) rating label | `string` | `undefined` |
| `maxRating` | `max-rating` | The upper limit of the rating | `number` | `5` |
| `minRating` | `min-rating` | The lower limit of the rating. In cases where | `number` | `0` |
| `rating` | `rating` | Represents the current value of the rating | `number` | `0` |
| `readonly` | `readonly` | makes the rating non-interactive (but still accessible) | `boolean` | `false` |
| `starSize` | `star-size` | The lower limit of the rating. In cases where | `"large" \| "small"` | `'large'` |
| Property | Attribute | Description | Type | Default |
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ----------------------------- |
| `ariaLabelTranslation` | `aria-label-translation` | a11y text for getting meaningful value. `$rating` and `$max` (deprecated `$maxRating`) are template variables and will be replaces by their corresponding properties. | `string` | `'$rating out of $max stars'` |
| `disabled` | `disabled` | disables input | `boolean` | `false` |
| `label` | `label` | (optional) rating label | `string` | `undefined` |
| `max` | `max` | The upper limit of the rating | `number` | `5` |
| `maxRating` | `max-rating` | Deprecated; max should be used instead of maxRating | `number` | `5` |
| `minRating` | `min-rating` | Deprecated; The lower limit of the rating | `number` | `0` |
| `rating` | `rating` | Represents the current value of the rating | `number` | `0` |
| `readonly` | `readonly` | makes the rating non-interactive (but still accessible) | `boolean` | `false` |
| `size` | `size` | size of the stars | `"large" \| "small"` | `'large'` |
| `starSize` | `star-size` | Deprecated; size should be used instead of starSize | `"large" \| "small"` | `'large'` |


## Events
Expand Down
Loading

0 comments on commit 3ceb6c1

Please sign in to comment.