feat: add input stepper component
This commit is contained in:
parent
526aee2006
commit
ba72b32b00
11 changed files with 527 additions and 18 deletions
5
.changeset/stale-moons-wait.md
Normal file
5
.changeset/stale-moons-wait.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/input-stepper': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Release initial version of an input stepper
|
||||||
|
|
@ -54,6 +54,7 @@ The accessibility column indicates whether the functionality is accessible in it
|
||||||
| [input-email](https://lion-web-components.netlify.app/?path=/docs/forms-input-email--main) | [](https://www.npmjs.com/package/@lion/input-email) | Input element for e-mails | ✔️ |
|
| [input-email](https://lion-web-components.netlify.app/?path=/docs/forms-input-email--main) | [](https://www.npmjs.com/package/@lion/input-email) | Input element for e-mails | ✔️ |
|
||||||
| [input-iban](https://lion-web-components.netlify.app/?path=/docs/forms-input-iban--main) | [](https://www.npmjs.com/package/@lion/input-iban) | Input element for IBANs | ✔️ |
|
| [input-iban](https://lion-web-components.netlify.app/?path=/docs/forms-input-iban--main) | [](https://www.npmjs.com/package/@lion/input-iban) | Input element for IBANs | ✔️ |
|
||||||
| [input-range](https://lion-web-components.netlify.app/?path=/docs/forms-input-range--main) | [](https://www.npmjs.com/package/@lion/input-range) | Input element for a range of values | ✔️ |
|
| [input-range](https://lion-web-components.netlify.app/?path=/docs/forms-input-range--main) | [](https://www.npmjs.com/package/@lion/input-range) | Input element for a range of values | ✔️ |
|
||||||
|
| [input-stepper](https://lion-web-components.netlify.app/?path=/docs/forms-input-stepper--main) | [](https://www.npmjs.com/package/@lion/input-stepper) | Input stepper element for the predefined range | ✔️ |
|
||||||
| [radio-group](https://lion-web-components.netlify.app/?path=/docs/forms-radio-group--main) | [](https://www.npmjs.com/package/@lion/radio-group) | Group of radios | ✔️ |
|
| [radio-group](https://lion-web-components.netlify.app/?path=/docs/forms-radio-group--main) | [](https://www.npmjs.com/package/@lion/radio-group) | Group of radios | ✔️ |
|
||||||
| [select](https://lion-web-components.netlify.app/?path=/docs/forms-select--main) | [](https://www.npmjs.com/package/@lion/select) | Simple native dropdown element | ✔️ |
|
| [select](https://lion-web-components.netlify.app/?path=/docs/forms-select--main) | [](https://www.npmjs.com/package/@lion/select) | Simple native dropdown element | ✔️ |
|
||||||
| [select-rich](https://lion-web-components.netlify.app/?path=/docs/forms-select-rich--main) | [](https://www.npmjs.com/package/@lion/select-rich) | 'rich' version of the native dropdown element | [#243][i243] |
|
| [select-rich](https://lion-web-components.netlify.app/?path=/docs/forms-select-rich--main) | [](https://www.npmjs.com/package/@lion/select-rich) | 'rich' version of the native dropdown element | [#243][i243] |
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ For a more in depth description look into the [Form System Overview](?path=/docs
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
| Package | Version | Description |
|
| Package | Version | Description |
|
||||||
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
|
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
||||||
| [checkbox-group](?path=/docs/forms-checkbox-group--main) | [](https://www.npmjs.com/package/@lion/checkbox-group) | Group of checkboxes |
|
| [checkbox-group](?path=/docs/forms-checkbox-group--main) | [](https://www.npmjs.com/package/@lion/checkbox-group) | Group of checkboxes |
|
||||||
| [form-core](?path=/docs/forms-system-overview--page) | [](https://www.npmjs.com/package/@lion/form-core) | Core functionality for all controls |
|
| [form-core](?path=/docs/forms-system-overview--page) | [](https://www.npmjs.com/package/@lion/form-core) | Core functionality for all controls |
|
||||||
| [form-integrations](?path=/docs/forms-features-overview--main) | [](https://www.npmjs.com/package/@lion/form-integrations) | Shows form elements in an integrated way |
|
| [form-integrations](?path=/docs/forms-features-overview--main) | [](https://www.npmjs.com/package/@lion/form-integrations) | Shows form elements in an integrated way |
|
||||||
|
|
@ -34,6 +34,7 @@ For a more in depth description look into the [Form System Overview](?path=/docs
|
||||||
| [input-email](?path=/docs/forms-input-email--main) | [](https://www.npmjs.com/package/@lion/input-email) | Input element for e-mails |
|
| [input-email](?path=/docs/forms-input-email--main) | [](https://www.npmjs.com/package/@lion/input-email) | Input element for e-mails |
|
||||||
| [input-iban](?path=/docs/forms-input-iban--main) | [](https://www.npmjs.com/package/@lion/input-iban) | Input element for IBANs |
|
| [input-iban](?path=/docs/forms-input-iban--main) | [](https://www.npmjs.com/package/@lion/input-iban) | Input element for IBANs |
|
||||||
| [input-range](?path=/docs/forms-input-range--main) | [](https://www.npmjs.com/package/@lion/input-range) | Input element for a range of values |
|
| [input-range](?path=/docs/forms-input-range--main) | [](https://www.npmjs.com/package/@lion/input-range) | Input element for a range of values |
|
||||||
|
| [input-stepper](?path=/docs/forms-input-stepper--main) | [](https://www.npmjs.com/package/@lion/input-stepper) | Input stepper element for the predefined range |
|
||||||
| [radio-group](?path=/docs/forms-radio-group--main) | [](https://www.npmjs.com/package/@lion/radio-group) | Group of radios |
|
| [radio-group](?path=/docs/forms-radio-group--main) | [](https://www.npmjs.com/package/@lion/radio-group) | Group of radios |
|
||||||
| [select](?path=/docs/forms-select--main) | [](https://www.npmjs.com/package/@lion/select) | Simple native dropdown element |
|
| [select](?path=/docs/forms-select--main) | [](https://www.npmjs.com/package/@lion/select) | Simple native dropdown element |
|
||||||
| [select-rich](?path=/docs/forms-select-rich--main) | [](https://www.npmjs.com/package/@lion/select-rich) | 'rich' version of the native dropdown element |
|
| [select-rich](?path=/docs/forms-select-rich--main) | [](https://www.npmjs.com/package/@lion/select-rich) | 'rich' version of the native dropdown element |
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import '@lion/input-datepicker/lion-input-datepicker.js';
|
||||||
import '@lion/input-email/lion-input-email.js';
|
import '@lion/input-email/lion-input-email.js';
|
||||||
import '@lion/input-iban/lion-input-iban.js';
|
import '@lion/input-iban/lion-input-iban.js';
|
||||||
import '@lion/input-range/lion-input-range.js';
|
import '@lion/input-range/lion-input-range.js';
|
||||||
|
import '@lion/input-stepper/lion-input-stepper.js';
|
||||||
import '@lion/input/lion-input.js';
|
import '@lion/input/lion-input.js';
|
||||||
import '@lion/radio-group/lion-radio-group.js';
|
import '@lion/radio-group/lion-radio-group.js';
|
||||||
import '@lion/radio-group/lion-radio.js';
|
import '@lion/radio-group/lion-radio.js';
|
||||||
|
|
@ -123,6 +124,12 @@ export const main = () => {
|
||||||
>
|
>
|
||||||
<lion-checkbox label="I blindly accept all terms and conditions"></lion-checkbox>
|
<lion-checkbox label="I blindly accept all terms and conditions"></lion-checkbox>
|
||||||
</lion-checkbox-group>
|
</lion-checkbox-group>
|
||||||
|
<lion-input-stepper max="5" min="0" name="rsvp">
|
||||||
|
<label slot="label">RSVP</label>
|
||||||
|
<div slot="help-text">
|
||||||
|
Max. 5 guests
|
||||||
|
</div>
|
||||||
|
</lion-input-stepper>
|
||||||
<lion-textarea name="comments" label="Comments"></lion-textarea>
|
<lion-textarea name="comments" label="Comments"></lion-textarea>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<lion-button raised>Submit</lion-button>
|
<lion-button raised>Submit</lion-button>
|
||||||
|
|
|
||||||
1
packages/input-stepper/CHANGELOG.md
Normal file
1
packages/input-stepper/CHANGELOG.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Change Log
|
||||||
136
packages/input-stepper/README.md
Normal file
136
packages/input-stepper/README.md
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Input Stepper
|
||||||
|
|
||||||
|
`lion-input-stepper` enables the user to increase and decrease a numeric value by predefined range. It is a combination of two buttons and a number input field with an optional slot `after` to suffix the extra information.
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import { html } from 'lit-html';
|
||||||
|
import '@lion/form/lion-form.js';
|
||||||
|
import './lion-input-stepper.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Forms/Input Stepper',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const main = () => html`
|
||||||
|
<lion-input-stepper max="5" min="0" name="count">
|
||||||
|
<label slot="label">RSVP</label>
|
||||||
|
<div slot="help-text">Max. 5 guests</div>
|
||||||
|
</lion-input-stepper>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Based on [lion-input](?path=/docs/forms-input--main#input).
|
||||||
|
- Set `min` and `max` value to define the range.
|
||||||
|
- Set `step` value in integer or decimal to increase and decrease the value.
|
||||||
|
- Use `ArrowUp` or `ArrowDown` to update the value.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i --save @lion/input-stepper
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { LionInputStepper } from '@lion/input-stepper';
|
||||||
|
// or
|
||||||
|
import '@lion/input-stepper/lion-input-stepper.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<lion-input-stepper max="5" min="0" name="count">
|
||||||
|
<label slot="label">RSVP</label>
|
||||||
|
<div slot="help-text">Max. 5 guests</div>
|
||||||
|
</lion-input-stepper>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### Default with no specification
|
||||||
|
|
||||||
|
When no range or step is defined, it can go infinite with default step value as `1`. You can also specify prefix content using `after` slot.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const defaultMode = () => html`
|
||||||
|
<label>How old is the existence?</label>
|
||||||
|
<lion-input-stepper name="year">
|
||||||
|
<div slot="after">In Billion Years</div>
|
||||||
|
</lion-input-stepper>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step and Value
|
||||||
|
|
||||||
|
Use `step` attribute to specify the incrementor or decrementor difference and `value` to set the default value.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const steps = () => html`
|
||||||
|
<p><strong>Min:</strong> 100, <strong>Value:</strong> 200, <strong>Step:</strong> 100</p>
|
||||||
|
<lion-input-stepper min="100" step="100" name="value" value="200"></lion-input-stepper>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Range
|
||||||
|
|
||||||
|
Use `min` and `max` attribute to specify range.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const range = () => html`
|
||||||
|
<p><strong>Min:</strong> 200, <strong>Max:</strong> 500, <strong>Step:</strong> 100</p>
|
||||||
|
<lion-input-stepper min="200" max="500" name="value" step="100" value="200"></lion-input-stepper>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Validation
|
||||||
|
|
||||||
|
Only numbers are allowed in the field.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const validation = () => html`
|
||||||
|
<p>
|
||||||
|
<strong>Min:</strong> 100, <strong>Max:</strong> 500, <strong>Step:</strong> 100,
|
||||||
|
<strong>Value:</strong> Test
|
||||||
|
</p>
|
||||||
|
<lion-input-stepper min="100" max="500" name="value" step="100" value="Test"></lion-input-stepper>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Form
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const usingForm = () => html`
|
||||||
|
<lion-form
|
||||||
|
@submit=${e => {
|
||||||
|
console.log(e.target.serializedValue);
|
||||||
|
const code = document.getElementById('code');
|
||||||
|
code.style = 'background-color:#DEDEDE;padding:12px;';
|
||||||
|
code.innerHTML = `<code>${JSON.stringify(e.target.serializedValue, null, 4)}</code>`;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<form>
|
||||||
|
<lion-input name="fullname" label="Full name"></lion-input>
|
||||||
|
<br />
|
||||||
|
<lion-input-stepper min="0" max="5" name="count">
|
||||||
|
<label slot="label">RSVP</label>
|
||||||
|
<div slot="help-text">Max. 5 guests</div>
|
||||||
|
</lion-input-stepper>
|
||||||
|
<br />
|
||||||
|
<lion-button raised>Submit</lion-button>
|
||||||
|
<lion-button
|
||||||
|
type="button"
|
||||||
|
raised
|
||||||
|
@click=${ev => ev.currentTarget.parentElement.parentElement.resetGroup()}
|
||||||
|
>Reset</lion-button
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
</lion-form>
|
||||||
|
<pre id="code"></pre>
|
||||||
|
`;
|
||||||
|
```
|
||||||
1
packages/input-stepper/index.js
Normal file
1
packages/input-stepper/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { LionInputStepper } from './src/LionInputStepper.js';
|
||||||
3
packages/input-stepper/lion-input-stepper.js
Normal file
3
packages/input-stepper/lion-input-stepper.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { LionInputStepper } from './src/LionInputStepper.js';
|
||||||
|
|
||||||
|
customElements.define('lion-input-stepper', LionInputStepper);
|
||||||
48
packages/input-stepper/package.json
Normal file
48
packages/input-stepper/package.json
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "@lion/input-stepper",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "This component enables the user to increase and decrease a numeric value by predefined range.",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "ing-bank",
|
||||||
|
"homepage": "https://github.com/ing-bank/lion/",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ing-bank/lion.git",
|
||||||
|
"directory": "packages/input-stepper"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"module": "index.js",
|
||||||
|
"files": [
|
||||||
|
"*.d.ts",
|
||||||
|
"*.js",
|
||||||
|
"docs",
|
||||||
|
"src",
|
||||||
|
"test",
|
||||||
|
"test-helpers",
|
||||||
|
"translations",
|
||||||
|
"types"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"prepublishOnly": "../../scripts/npm-prepublish.js",
|
||||||
|
"start": "cd ../../ && yarn dev-server --open packages/input-stepper/README.md",
|
||||||
|
"test": "cd ../../ && yarn test:browser --grep \"packages/input-stepper/test/**/*.test.js\"",
|
||||||
|
"test:watch": "cd ../../ && yarn test:browser:watch --grep \"packages/input-stepper/test/**/*.test.js\""
|
||||||
|
},
|
||||||
|
"sideEffects": [
|
||||||
|
"lion-input-stepper.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@lion/core": "0.12.0",
|
||||||
|
"@lion/form-core": "0.6.1",
|
||||||
|
"@lion/input": "0.9.2"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"input",
|
||||||
|
"input-stepper",
|
||||||
|
"lion",
|
||||||
|
"web-components"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
238
packages/input-stepper/src/LionInputStepper.js
Normal file
238
packages/input-stepper/src/LionInputStepper.js
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
import { html, css } from '@lion/core';
|
||||||
|
import { LionInput } from '@lion/input';
|
||||||
|
import { IsNumber, MinNumber, MaxNumber } from '@lion/form-core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `LionInputStepper` is a class for custom input-stepper element (`<lion-input-stepper>` web component).
|
||||||
|
*
|
||||||
|
* @customElement lion-input-stepper
|
||||||
|
* @extends LitElement
|
||||||
|
*/
|
||||||
|
export class LionInputStepper extends LionInput {
|
||||||
|
static get styles() {
|
||||||
|
return [
|
||||||
|
super.styles,
|
||||||
|
css`
|
||||||
|
.input-group__container > .input-group__input ::slotted(.form-control) {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
min: Number,
|
||||||
|
max: Number,
|
||||||
|
step: Number,
|
||||||
|
modelValue: Number,
|
||||||
|
__disableIncrementor: Boolean,
|
||||||
|
__disableDecrementor: Boolean,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentValue() {
|
||||||
|
return parseFloat(this.value || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.parser = modelValue => parseFloat(modelValue);
|
||||||
|
this.__disableIncrementor = false;
|
||||||
|
this.__disableDecrementor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
if (super.connectedCallback) {
|
||||||
|
super.connectedCallback();
|
||||||
|
}
|
||||||
|
this.role = 'spinbutton';
|
||||||
|
this.addEventListener('keydown', this.__keyDownHandler);
|
||||||
|
this._inputNode.setAttribute('inputmode', 'decimal');
|
||||||
|
this._inputNode.setAttribute('autocomplete', 'off');
|
||||||
|
this.step = this.hasAttribute('step') ? this.step : 1;
|
||||||
|
this.__setAriaLabelsAndValidator();
|
||||||
|
this.__toggleSpinnerButtonsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
if (super.disconnectedCallback) {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
this.removeEventListener('keydown', this.__keyDownHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update native input values
|
||||||
|
* @param {Object} changedProps - changed props
|
||||||
|
*/
|
||||||
|
updated(changedProps) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
|
||||||
|
if (changedProps.has('min')) {
|
||||||
|
this._inputNode.min = this.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProps.has('max')) {
|
||||||
|
this._inputNode.max = this.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProps.has('step')) {
|
||||||
|
this._inputNode.step = this.step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set aria labels and apply validators
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__setAriaLabelsAndValidator() {
|
||||||
|
this.values = {
|
||||||
|
max: parseFloat(this.max || Infinity),
|
||||||
|
min: parseFloat(this.min || Infinity),
|
||||||
|
step: parseFloat(this.step),
|
||||||
|
};
|
||||||
|
|
||||||
|
const ariaAttributes = {
|
||||||
|
'aria-valuemax': this.values.max,
|
||||||
|
'aria-valuemin': this.values.min,
|
||||||
|
};
|
||||||
|
|
||||||
|
let validators = Object.entries(ariaAttributes)
|
||||||
|
.map(([key, val]) => {
|
||||||
|
if (val !== Infinity) {
|
||||||
|
this.setAttribute(key, val);
|
||||||
|
return key === 'aria-valuemax' ? new MaxNumber(val) : new MinNumber(val);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(validator => validator);
|
||||||
|
validators = [new IsNumber(), ...validators];
|
||||||
|
this.defaultValidators.push(...validators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update values on keyboard arrow up and down event
|
||||||
|
* @param {KeyboardEvent} e - keyboard event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__keyDownHandler(e) {
|
||||||
|
if (e.key === 'ArrowUp') {
|
||||||
|
this.__increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
this.__decrement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle disabled state for the buttons
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__toggleSpinnerButtonsState() {
|
||||||
|
const { min, max } = this.values;
|
||||||
|
this.__disableIncrementor = this.currentValue >= max && max !== Infinity;
|
||||||
|
this.__disableDecrementor = this.currentValue <= min && min !== Infinity;
|
||||||
|
this.setAttribute('aria-valuenow', this.currentValue);
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('user-input-changed', {
|
||||||
|
bubbles: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the value based on given step or default step value is 1
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__increment() {
|
||||||
|
const { step, max } = this.values;
|
||||||
|
const newValue = this.currentValue + step;
|
||||||
|
if (newValue <= max || max === Infinity) {
|
||||||
|
this.value = newValue;
|
||||||
|
this.__toggleSpinnerButtonsState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement the value based on given step or default step value is 1
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__decrement() {
|
||||||
|
const { step, min } = this.values;
|
||||||
|
const newValue = this.currentValue - step;
|
||||||
|
if (newValue >= min || min === Infinity) {
|
||||||
|
this.value = newValue;
|
||||||
|
this.__toggleSpinnerButtonsState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle +/- buttons on change
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
_onChange() {
|
||||||
|
super._onChange();
|
||||||
|
this.__toggleSpinnerButtonsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override after template to none
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_inputGroupAfterTemplate() {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override before template to none
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_inputGroupBeforeTemplate() {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override prefix template for the increment button
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_inputGroupPrefixTemplate() {
|
||||||
|
return html`
|
||||||
|
<button
|
||||||
|
?disabled=${this.disabled || this.readOnly || this.__disableDecrementor}
|
||||||
|
@click=${this.__decrement}
|
||||||
|
tabindex="-1"
|
||||||
|
name="decrement"
|
||||||
|
type="button"
|
||||||
|
aria-label="decrement"
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override suffix template for the decrement button and add after slot
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_inputGroupSuffixTemplate() {
|
||||||
|
return html`
|
||||||
|
<button
|
||||||
|
?disabled=${this.disabled || this.readOnly || this.__disableIncrementor}
|
||||||
|
@click=${this.__increment}
|
||||||
|
tabindex="-1"
|
||||||
|
name="increment"
|
||||||
|
type="button"
|
||||||
|
aria-label="increment"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
<slot name="after"></slot>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
packages/input-stepper/test/lion-input-stepper.test.js
Normal file
68
packages/input-stepper/test/lion-input-stepper.test.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { expect, fixture, nextFrame, html } from '@open-wc/testing';
|
||||||
|
import '../lion-input-stepper.js';
|
||||||
|
|
||||||
|
const defaultInputStepper = html`
|
||||||
|
<lion-input-stepper name="year" label="Years"></lion-input-stepper>
|
||||||
|
`;
|
||||||
|
const inputStepperWithAttrs = html`<lion-input-stepper min="100" max="200"></lion-input-stepper>`;
|
||||||
|
|
||||||
|
describe('<lion-input-stepper>', () => {
|
||||||
|
describe('Stepper', () => {
|
||||||
|
it('has a type text', async () => {
|
||||||
|
const el = await fixture(defaultInputStepper);
|
||||||
|
expect(el._inputNode.type).to.equal('text');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('User interaction', () => {
|
||||||
|
it('should increment the value to 1 on + button click', async () => {
|
||||||
|
const el = await fixture(defaultInputStepper);
|
||||||
|
expect(el.value).to.equal('');
|
||||||
|
const incrementButton = el.shadowRoot.querySelector('[name=increment]');
|
||||||
|
incrementButton.dispatchEvent(new Event('click'));
|
||||||
|
expect(el.value).to.equal('1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decrement the value to -1 on - button click', async () => {
|
||||||
|
const el = await fixture(defaultInputStepper);
|
||||||
|
expect(el.value).to.equal('');
|
||||||
|
const incrementButton = el.shadowRoot.querySelector('[name=decrement]');
|
||||||
|
incrementButton.dispatchEvent(new Event('click'));
|
||||||
|
expect(el.value).to.equal('-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update min and max attributes when min and max property change', async () => {
|
||||||
|
const el = await fixture(inputStepperWithAttrs);
|
||||||
|
el.min = '100';
|
||||||
|
el.max = '200';
|
||||||
|
await nextFrame();
|
||||||
|
expect(el._inputNode.min).to.equal(el.min);
|
||||||
|
expect(el._inputNode.max).to.equal(el.max);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Accessibility', () => {
|
||||||
|
it('is a11y AXE accessible', async () => {
|
||||||
|
const el = await fixture(defaultInputStepper);
|
||||||
|
await expect(el).to.be.accessible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is accessible when disabled', async () => {
|
||||||
|
const el = await fixture(`<lion-input-stepper label="rsvp" disabled></lion-input-stepper>`);
|
||||||
|
await expect(el).to.be.accessible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds aria-valuemax and aria-valuemin when min and max are provided', async () => {
|
||||||
|
const el = await fixture(inputStepperWithAttrs);
|
||||||
|
expect(el).to.have.attribute('aria-valuemax', '200');
|
||||||
|
expect(el).to.have.attribute('aria-valuemin', '100');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates aria-valuenow when stepper is changed', async () => {
|
||||||
|
const el = await fixture(inputStepperWithAttrs);
|
||||||
|
const incrementButton = el.shadowRoot.querySelector('[name=increment]');
|
||||||
|
incrementButton.dispatchEvent(new Event('click'));
|
||||||
|
expect(el).to.have.attribute('aria-valuenow', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue