diff --git a/src/number-spinner/README.md b/src/number-spinner/README.md new file mode 100644 index 0000000..a844f3e --- /dev/null +++ b/src/number-spinner/README.md @@ -0,0 +1,45 @@ +# Form + + + + + + +
+

Built by the super talented team at Travelopia.

+
+ +
+ +## Sample Usage + +This is a number spinner component that is designed to be highly extendable. + +Example: + +```js +// Import the component as needed: +import '@travelopia/web-components/dist/number-spinner'; + +// TypeScript usage: +import { TPNumberSpinner, TPNumberSpinnerInput, TPNumberSpinnerIncrement, TPNumberSpinnerDecrement } from '@travelopia/web-components'; + +``` + +```html + + + + + + + +``` + +## Attributes + +| Attribute | Required | Values | Notes | +|-----------|----------|-----------------------|----------------------------------------| +| min | No | | The minimum value of the spinner | +| max | No | | The maxium value of the spinner | +| step | No | | The step of the spinner. Defaults to 1 | diff --git a/src/number-spinner/index.html b/src/number-spinner/index.html new file mode 100644 index 0000000..fd8c011 --- /dev/null +++ b/src/number-spinner/index.html @@ -0,0 +1,44 @@ + + + + + + + Web Component: Number Spinner + + + + + + +
+ + + + + + + + +

+ + + + + + + + + +

+ + + + + + + + +
+ + diff --git a/src/number-spinner/index.ts b/src/number-spinner/index.ts new file mode 100644 index 0000000..de0506e --- /dev/null +++ b/src/number-spinner/index.ts @@ -0,0 +1,20 @@ +/** + * Styles. + */ +import './style.scss'; + +/** + * Components. + */ +import { TPNumberSpinnerInput } from './tp-number-spinner-input'; +import { TPNumberSpinnerIncrement } from './tp-number-spinner-increment'; +import { TPNumberSpinnerDecrement } from './tp-number-spinner-decrement'; +import { TPNumberSpinner } from './tp-number-spinner'; + +/** + * Register Components. + */ +customElements.define( 'tp-number-spinner-input', TPNumberSpinnerInput ); +customElements.define( 'tp-number-spinner-increment', TPNumberSpinnerIncrement ); +customElements.define( 'tp-number-spinner-decrement', TPNumberSpinnerDecrement ); +customElements.define( 'tp-number-spinner', TPNumberSpinner ); diff --git a/src/number-spinner/style.scss b/src/number-spinner/style.scss new file mode 100644 index 0000000..6d02b9a --- /dev/null +++ b/src/number-spinner/style.scss @@ -0,0 +1,3 @@ +tp-number-spinner { + display: contents; +} diff --git a/src/number-spinner/tp-number-spinner-decrement.ts b/src/number-spinner/tp-number-spinner-decrement.ts new file mode 100644 index 0000000..a5d8cb4 --- /dev/null +++ b/src/number-spinner/tp-number-spinner-decrement.ts @@ -0,0 +1,29 @@ +/** + * Internal dependencies. + */ +import { TPNumberSpinner } from './tp-number-spinner'; + +/** + * TP Number Spinner Decrement Element. + */ +export class TPNumberSpinnerDecrement extends HTMLElement { + /** + * Constructor. + */ + constructor() { + // Initialize parent. + super(); + + // Attach click event for decrement. + this.querySelector( 'button' )?.addEventListener( 'click', this.decrement.bind( this ) ); + } + + /** + * Decrement the value. + */ + decrement(): void { + // Run function on parent. + const numberSpinner: TPNumberSpinner | null = this.closest( 'tp-number-spinner' ); + numberSpinner?.decrement(); + } +} diff --git a/src/number-spinner/tp-number-spinner-increment.ts b/src/number-spinner/tp-number-spinner-increment.ts new file mode 100644 index 0000000..ace0abc --- /dev/null +++ b/src/number-spinner/tp-number-spinner-increment.ts @@ -0,0 +1,29 @@ +/** + * Internal dependencies. + */ +import { TPNumberSpinner } from './tp-number-spinner'; + +/** + * TP Number Spinner Increment Element. + */ +export class TPNumberSpinnerIncrement extends HTMLElement { + /** + * Constructor. + */ + constructor() { + // Initialize parent. + super(); + + // Attach click event for increment. + this.querySelector( 'button' )?.addEventListener( 'click', this.increment.bind( this ) ); + } + + /** + * Increment the value. + */ + increment(): void { + // Run function on parent. + const numberSpinner: TPNumberSpinner | null = this.closest( 'tp-number-spinner' ); + numberSpinner?.increment(); + } +} diff --git a/src/number-spinner/tp-number-spinner-input.ts b/src/number-spinner/tp-number-spinner-input.ts new file mode 100644 index 0000000..b5b16aa --- /dev/null +++ b/src/number-spinner/tp-number-spinner-input.ts @@ -0,0 +1,5 @@ +/** + * TP Number Spinner Input. + */ +export class TPNumberSpinnerInput extends HTMLElement { +} diff --git a/src/number-spinner/tp-number-spinner.ts b/src/number-spinner/tp-number-spinner.ts new file mode 100644 index 0000000..931489c --- /dev/null +++ b/src/number-spinner/tp-number-spinner.ts @@ -0,0 +1,140 @@ +/** + * TP Number Spinner Element. + */ +export class TPNumberSpinner extends HTMLElement { + /** + * Get minimum value. + * + * @return {number|null} The minimum value. + */ + get min(): number | null { + // Get minimum attribute. + const min: string | null = this.getAttribute( 'min' ); + + // Check if we have an attribute. + if ( min ) { + // Yep, return its value. + return parseInt( min ); + } + + // Nope, return null. + return null; + } + + /** + * Set minimum value. + * + * @param {number} min Minimum value. + */ + set min( min: number ) { + // Set attribute. + this.setAttribute( 'min', min.toString() ); + } + + /** + * Get maximum value. + * + * @return {number|null} The maximum value. + */ + get max(): number | null { + // Get maximum attribute. + const max: string | null = this.getAttribute( 'max' ); + + // Check if we have an attribute. + if ( max ) { + // Yep, return its value. + return parseInt( max ); + } + + // Nope, return null. + return null; + } + + /** + * Set maximum value. + * + * @param {number} max Maximum value. + */ + set max( max: number ) { + // Set attribute. + this.setAttribute( 'max', max.toString() ); + } + + /** + * Get current step. + * + * @return {number} Current step. + */ + get step(): number { + // Get step from attribute. + return parseInt( this.getAttribute( 'step' ) ?? '1' ); + } + + /** + * Set current step. + * + * @param {number} step Current step. + */ + set step( step: number ) { + // Set attribute. + this.setAttribute( 'step', step.toString() ); + } + + /** + * Get value. + * + * @return {number} The value. + */ + get value(): number { + // Get value from input. + return parseInt( this.querySelector( 'tp-number-spinner-input input' )?.getAttribute( 'value' ) ?? '0' ); + } + + /** + * Set current value. + * + * @param {number} value Current value. + */ + set value( value: number ) { + // Set input's value. + this.querySelector( 'tp-number-spinner-input input' )?.setAttribute( 'value', value.toString() ); + } + + /** + * Increment. + */ + increment(): void { + // Calculate new value. + const currentValue: number = this.value; + const max: number | null = this.max; + const newValue: number = currentValue + this.step; + + // Check if new value is greater than the maximum. + if ( max && newValue > max ) { + // Yes, that's not allowed. + return; + } + + // No, set its value. + this.value = newValue; + } + + /** + * Decrement. + */ + decrement(): void { + // Calculate new value. + const currentValue: number = this.value; + const min: number | null = this.min; + const newValue: number = currentValue - this.step; + + // Check if new value is less than the minumum. + if ( min && newValue < min ) { + // Yes, that's not allowed. + return; + } + + // No, set its value. + this.value = newValue; + } +} diff --git a/webpack.config.js b/webpack.config.js index 67df031..a347deb 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -84,6 +84,7 @@ module.exports = ( env ) => { 'multi-select': './src/multi-select/index.ts', lightbox: './src/lightbox/index.ts', 'toggle-attribute': './src/toggle-attribute/index.ts', + 'number-spinner': './src/number-spinner/index.ts', }, module: { rules: [