UNPKG

carbon-custom-elements

Version:

A Carbon Design System variant that's as easy to use as native HTML elements, with no framework tax, no framework silo.

1 lines 11 kB
{"version":3,"sources":["components/number-input/number-input.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGvE,OAAO,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,yBAAyB,IAAI,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAIpG;;GAEG;AACH,oBAAY,8BAA8B;IACxC,gBAAgB,qBAAqB;IACrC,gBAAgB,qBAAqB;CACtC;AAED;;;;;;GAMG;AAEH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,OAAO;IAChD;;OAEG;IAEH,SAAS,CAAC,MAAM,EAAG,gBAAgB,CAAC;IAEpC,aAAa;IAUb,mBAAmB,CAAC,KAAK,EAAE,MAAM;IAWjC,SAAS,CAAC,IAAI,SAAM;IAEpB,SAAS,CAAC,IAAI,SAAM;IAEpB,SAAS,CAAC,KAAK,SAAO;IAEtB,SAAS,CAAC,MAAM,SAAM;IAEtB;;OAEG;IAEH,WAAW,4BAAqC;IAEhD;;OAEG;IACH,IACI,GAAG,WAEN;IAED,IAAI,GAAG,CAAC,KAAK,QAAA,EAIZ;IAED;;OAEG;IACH,IACI,GAAG,WAEN;IAED,IAAI,GAAG,CAAC,KAAK,QAAA,EAIZ;IAED;;OAEG;IACH,IACI,IAAI,WAEP;IAED,IAAI,IAAI,CAAC,KAAK,QAAA,EAIb;IAED;;OAEG;IACH,IACI,KAAK,WAOR;IAED,IAAI,KAAK,CAAC,KAAK,QAAA,EAUd;IAED;;OAEG;IAEH,MAAM,UAAS;IAEf;;OAEG;IAEH,4BAA4B,SAA2B;IAEvD;;OAEG;IAEH,4BAA4B,SAA2B;IAEvD;;OAEG;IAEH,IAAI,aAAsB;IAE1B;;;;OAIG;IAEH,kBAAkB,SAAM;IAExB;;;;OAIG;IAEH,kBAAkB,SAAM;IAExB;;OAEG;IACH,MAAM;IAIN;;OAEG;IACH,QAAQ;IAIR,gBAAgB;IAIhB,MAAM;IA4HN,MAAM,CAAC,MAAM,MAAU;CACxB","file":"number-input.d.ts","sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2019, 2020\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { customElement, html, property, query } from 'lit-element';\nimport { classMap } from 'lit-html/directives/class-map';\nimport settings from 'carbon-components/es/globals/js/settings';\nimport WarningFilled16 from '@carbon/icons/lib/warning--filled/16';\nimport CaretUp16 from '@carbon/icons/lib/caret--up/16';\nimport CaretDown16 from '@carbon/icons/lib/caret--down/16';\nimport { FORM_ELEMENT_COLOR_SCHEME } from '../../globals/shared-enums';\nimport ifNonEmpty from '../../globals/directives/if-non-empty';\nimport styles from './number-input.scss';\nimport BXInput, { INPUT_SIZE } from '../input/input';\n\nexport { FORM_ELEMENT_COLOR_SCHEME as NUMBER_INPUT_COLOR_SCHEME } from '../../globals/shared-enums';\n\nconst { prefix } = settings;\n\n/**\n * Works in conjunction with VALIDATION_STATUS\n */\nexport enum NUMBER_INPUT_VALIDATION_STATUS {\n EXCEEDED_MAXIMUM = 'exceeded_maximum',\n EXCEEDED_MINIMUM = 'exceeded_minimum',\n}\n\n/**\n * Number input.\n * @element bx-number-input\n * @slot helper-text - The helper text.\n * @slot label-text - The label text.\n * @slot validity-message - The validity message. If present and non-empty, this input shows the UI of its invalid state.\n */\n@customElement(`${prefix}-number-input`)\nexport default class BXNumberInput extends BXInput {\n /**\n * The underlying input element\n */\n @query('input')\n protected _input!: HTMLInputElement;\n\n _testValidity() {\n if (this._input?.valueAsNumber > Number(this.max)) {\n return NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MAXIMUM;\n }\n if (this._input?.valueAsNumber < Number(this.min)) {\n return NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MINIMUM;\n }\n return super._testValidity();\n }\n\n _getValidityMessage(state: string) {\n if (Object.values(NUMBER_INPUT_VALIDATION_STATUS).includes(state as NUMBER_INPUT_VALIDATION_STATUS)) {\n const stateMessageMap = {\n [NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MAXIMUM]: this.validityMessageMax,\n [NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MINIMUM]: this.validityMessageMin,\n };\n return stateMessageMap[state];\n }\n return super._getValidityMessage(state);\n }\n\n protected _min = '';\n\n protected _max = '';\n\n protected _step = '1';\n\n protected _value = '';\n\n /**\n * The color scheme.\n */\n @property({ attribute: 'color-scheme', reflect: true })\n colorScheme = FORM_ELEMENT_COLOR_SCHEME.REGULAR;\n\n /**\n * The minimum value allowed in the input\n */\n @property({ reflect: true })\n get min() {\n return this._min.toString();\n }\n\n set min(value) {\n const oldValue = this.min;\n this._min = value;\n this.requestUpdate('min', oldValue);\n }\n\n /**\n * The maximum value allowed in the input\n */\n @property({ reflect: true })\n get max() {\n return this._max.toString();\n }\n\n set max(value) {\n const oldValue = this.max;\n this._max = value;\n this.requestUpdate('max', oldValue);\n }\n\n /**\n * The amount the value should increase or decrease by\n */\n @property({ reflect: true })\n get step() {\n return this._step.toString();\n }\n\n set step(value) {\n const oldValue = this.step;\n this._step = value;\n this.requestUpdate('step', oldValue);\n }\n\n /**\n * The value of the input.\n */\n @property({ reflect: true })\n get value() {\n // once we have the input we can directly query for the value\n if (this._input) {\n return this._input.value;\n }\n // but before then _value will work fine\n return this._value;\n }\n\n set value(value) {\n const oldValue = this._value;\n this._value = value;\n // make sure that lit-element updates the right properties\n this.requestUpdate('value', oldValue);\n // we set the value directly on the input (when available)\n // so that programatic manipulation updates the UI correctly\n if (this._input) {\n this._input.value = value;\n }\n }\n\n /**\n * Set to `true` to enable the mobile variant of the number input\n */\n @property({ type: Boolean, reflect: true })\n mobile = false;\n\n /**\n * Aria text for the button that increments the value\n */\n @property({ attribute: 'increment-button-assistive-text' })\n incrementButtonAssistiveText = 'increase number input';\n\n /**\n * Aria text for the button that decrements the value\n */\n @property({ attribute: 'decrement-button-assistive-text' })\n decrementButtonAssistiveText = 'decrease number input';\n\n /**\n * The input box size.\n */\n @property({ reflect: true })\n size = INPUT_SIZE.REGULAR;\n\n /**\n * The validity message shown when the value is greater than the maximum\n *\n * Also available via the `validity-message-max` slot\n */\n @property({ attribute: 'validity-message-max' })\n validityMessageMax = '';\n\n /**\n * The validity message shown when the value is less than the minimum\n *\n * Also available via the `validity-message-min` slot\n */\n @property({ attribute: 'validity-message-min' })\n validityMessageMin = '';\n\n /**\n * Handles incrementing the value in the input\n */\n stepUp() {\n this._input.stepUp();\n }\n\n /**\n * Handles decrementing the value in the input\n */\n stepDown() {\n this._input.stepDown();\n }\n\n createRenderRoot() {\n return this.attachShadow({ mode: 'open', delegatesFocus: true });\n }\n\n render() {\n const { _handleInput: handleInput } = this;\n\n const invalidIcon = WarningFilled16({ class: `${prefix}--number__invalid` });\n\n const validity = this._testValidity();\n\n const isGenericallyInvalid = () =>\n this.invalid &&\n validity !== NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MAXIMUM &&\n validity !== NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MINIMUM;\n\n const wrapperClasses = classMap({\n [`${prefix}--number`]: true,\n [`${prefix}--number--${this.colorScheme}`]: this.colorScheme,\n [`${prefix}--number--mobile`]: this.mobile,\n [`${prefix}--number--${this.size}`]: this.size,\n });\n\n const labelClasses = classMap({\n [`${prefix}--label`]: true,\n [`${prefix}--label--disabled`]: this.disabled,\n });\n\n const helperTextClasses = classMap({\n [`${prefix}--form__helper-text`]: true,\n [`${prefix}--form__helper-text--disabled`]: this.disabled,\n });\n\n const incrementButton = html`\n <button\n class=\"${prefix}--number__control-btn up-icon\"\n aria-label=\"${this.incrementButtonAssistiveText}\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n type=\"button\"\n ?disabled=${this.disabled}\n @click=${this.stepUp}\n >\n ${CaretUp16()}\n </button>\n `;\n const decrementButton = html`\n <button\n class=\"${prefix}--number__control-btn down-icon\"\n aria-label=\"${this.decrementButtonAssistiveText}\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n type=\"button\"\n ?disabled=${this.disabled}\n @click=${this.stepDown}\n >\n ${CaretDown16()}\n </button>\n `;\n\n const input = html`\n <input\n ?autocomplete=\"${this.autocomplete}\"\n ?autofocus=\"${this.autofocus}\"\n ?data-invalid=\"${this.invalid}\"\n ?disabled=\"${this.disabled}\"\n id=\"input\"\n name=\"${ifNonEmpty(this.name)}\"\n pattern=\"${ifNonEmpty(this.pattern)}\"\n placeholder=\"${ifNonEmpty(this.placeholder)}\"\n ?readonly=\"${this.readonly}\"\n ?required=\"${this.required}\"\n type=\"number\"\n .value=\"${this._value}\"\n @input=\"${handleInput}\"\n min=\"${ifNonEmpty(this.min)}\"\n max=\"${ifNonEmpty(this.max)}\"\n step=\"${ifNonEmpty(this.step)}\"\n role=\"alert\"\n aria-atomic=\"true\"\n />\n `;\n\n const defaultLayout = html`\n ${this.invalid ? invalidIcon : null} ${input}\n <div class=\"${prefix}--number__controls\">\n ${incrementButton} ${decrementButton}\n </div>\n `;\n\n const mobileLayout = html`\n ${decrementButton} ${input} ${incrementButton}\n `;\n\n return html`\n <div class=\"${wrapperClasses}\" ?data-invalid=${this.invalid}>\n <label class=\"${labelClasses}\" for=\"input\">\n <slot name=\"label-text\">\n ${this.labelText}\n </slot>\n </label>\n <div class=\"${helperTextClasses}\">\n <slot name=\"helper-text\">\n ${this.helperText}\n </slot>\n </div>\n <div class=\"${prefix}--number__input-wrapper\">\n ${this.mobile ? mobileLayout : defaultLayout}\n </div>\n <div class=\"${prefix}--form-requirement\" ?hidden=\"${!isGenericallyInvalid()}\">\n <slot name=\"validity-message\">\n ${this.validityMessage}\n </slot>\n </div>\n <div class=\"${prefix}--form-requirement\" ?hidden=\"${validity !== NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MAXIMUM}\">\n <slot name=\"validity-message-max\">\n ${this.validityMessageMax}\n </slot>\n </div>\n <div class=\"${prefix}--form-requirement\" ?hidden=\"${validity !== NUMBER_INPUT_VALIDATION_STATUS.EXCEEDED_MINIMUM}\">\n <slot name=\"validity-message-min\">\n ${this.validityMessageMin}\n </slot>\n </div>\n </div>\n `;\n }\n\n static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader\n}\n"]}