Skip to content

Commit

Permalink
feat(number-input): create new component to improve type safty
Browse files Browse the repository at this point in the history
  • Loading branch information
hirsch88 committed Feb 25, 2022
1 parent d3a6e14 commit cf6a4db
Show file tree
Hide file tree
Showing 16 changed files with 675 additions and 31 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
],
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': [
Expand Down
2 changes: 1 addition & 1 deletion packages/components/.build/stencil/stencil.bindings.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const vueComponentModels: ComponentModelConfig[] = [
targetAttr: 'checked',
},
{
elements: ['bal-input', 'bal-textarea', 'bal-slider'],
elements: ['bal-input', 'bal-number-input', 'bal-textarea', 'bal-slider'],
event: 'balInput',
targetAttr: 'value',
},
Expand Down
137 changes: 131 additions & 6 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ export namespace Components {
*/
"debounce": number;
/**
* Defines the allowed decimal points for the `number-input`.
* @deprecated Defines the allowed decimal points for the `number-input`. Use the <bal-number-input> component instead.
*/
"decimal"?: number;
/**
Expand Down Expand Up @@ -767,7 +767,7 @@ export namespace Components {
*/
"name": string;
/**
* If `true` on mobile device the number keypad is active
* @deprecated If `true` on mobile device the number keypad is active. Use the <bal-number-input> component instead.
*/
"numberInput": boolean;
/**
Expand Down Expand Up @@ -805,7 +805,7 @@ export namespace Components {
/**
* The value of the input.
*/
"value"?: string | number;
"value"?: string;
}
interface BalInputGroup {
/**
Expand Down Expand Up @@ -1015,6 +1015,60 @@ export namespace Components {
*/
"color": '' | ColorTypes;
}
interface BalNumberInput {
/**
* Set the amount of time, in milliseconds, to wait to trigger the `balChange` event after each keystroke. This also impacts form bindings such as `ngModel` or `v-model`.
*/
"debounce": number;
/**
* Defines the allowed decimal points for the `number-input`.
*/
"decimal": number;
/**
* If `true` the input is disabled
*/
"disabled": boolean;
/**
* Returns the native `<input>` element used under the hood.
*/
"getInputElement": () => Promise<HTMLInputElement>;
/**
* If `true` the component gets a invalid style.
*/
"invalid": boolean;
/**
* The name of the control, which is submitted with the form data.
*/
"name": string;
/**
* Instructional text that shows before the input has a value.
*/
"placeholder"?: string | null;
/**
* If `true`, the user cannot modify the value.
*/
"readonly": boolean;
/**
* If `true`, the user must fill in a value before submitting a form.
*/
"required": boolean;
/**
* Sets blur on the native `input` in `ion-input`. Use this method instead of the global `input.blur()`.
*/
"setBlur": () => Promise<void>;
/**
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global `input.focus()`.
*/
"setFocus": () => Promise<void>;
/**
* Adds a suffix the the input-value after blur.
*/
"suffix": string;
/**
* The value of the input.
*/
"value"?: number | null;
}
interface BalPagination {
/**
* Disables component
Expand Down Expand Up @@ -1974,6 +2028,12 @@ declare global {
prototype: HTMLBalNotificationElement;
new (): HTMLBalNotificationElement;
};
interface HTMLBalNumberInputElement extends Components.BalNumberInput, HTMLStencilElement {
}
var HTMLBalNumberInputElement: {
prototype: HTMLBalNumberInputElement;
new (): HTMLBalNumberInputElement;
};
interface HTMLBalPaginationElement extends Components.BalPagination, HTMLStencilElement {
}
var HTMLBalPaginationElement: {
Expand Down Expand Up @@ -2176,6 +2236,7 @@ declare global {
"bal-navbar-menu-start": HTMLBalNavbarMenuStartElement;
"bal-notices": HTMLBalNoticesElement;
"bal-notification": HTMLBalNotificationElement;
"bal-number-input": HTMLBalNumberInputElement;
"bal-pagination": HTMLBalPaginationElement;
"bal-popover": HTMLBalPopoverElement;
"bal-popover-content": HTMLBalPopoverContentElement;
Expand Down Expand Up @@ -2918,7 +2979,7 @@ declare namespace LocalJSX {
*/
"debounce"?: number;
/**
* Defines the allowed decimal points for the `number-input`.
* @deprecated Defines the allowed decimal points for the `number-input`. Use the <bal-number-input> component instead.
*/
"decimal"?: number;
/**
Expand Down Expand Up @@ -2963,7 +3024,7 @@ declare namespace LocalJSX {
*/
"name"?: string;
/**
* If `true` on mobile device the number keypad is active
* @deprecated If `true` on mobile device the number keypad is active. Use the <bal-number-input> component instead.
*/
"numberInput"?: boolean;
/**
Expand Down Expand Up @@ -3021,7 +3082,7 @@ declare namespace LocalJSX {
/**
* The value of the input.
*/
"value"?: string | number;
"value"?: string;
}
interface BalInputGroup {
/**
Expand Down Expand Up @@ -3236,6 +3297,68 @@ declare namespace LocalJSX {
*/
"color"?: '' | ColorTypes;
}
interface BalNumberInput {
/**
* Set the amount of time, in milliseconds, to wait to trigger the `balChange` event after each keystroke. This also impacts form bindings such as `ngModel` or `v-model`.
*/
"debounce"?: number;
/**
* Defines the allowed decimal points for the `number-input`.
*/
"decimal"?: number;
/**
* If `true` the input is disabled
*/
"disabled"?: boolean;
/**
* If `true` the component gets a invalid style.
*/
"invalid"?: boolean;
/**
* The name of the control, which is submitted with the form data.
*/
"name"?: string;
/**
* Emitted when the input loses focus.
*/
"onBalBlur"?: (event: CustomEvent<FocusEvent>) => void;
/**
* Emitted when the value has changed.
*/
"onBalChange"?: (event: CustomEvent<number | null | undefined>) => void;
/**
* Emitted when the input has focus.
*/
"onBalFocus"?: (event: CustomEvent<FocusEvent>) => void;
/**
* Emitted when a keyboard input occurred.
*/
"onBalInput"?: (event: CustomEvent<number | null | undefined>) => void;
/**
* Emitted when a keyboard key has pressed.
*/
"onBalKeyPress"?: (event: CustomEvent<KeyboardEvent>) => void;
/**
* Instructional text that shows before the input has a value.
*/
"placeholder"?: string | null;
/**
* If `true`, the user cannot modify the value.
*/
"readonly"?: boolean;
/**
* If `true`, the user must fill in a value before submitting a form.
*/
"required"?: boolean;
/**
* Adds a suffix the the input-value after blur.
*/
"suffix"?: string;
/**
* The value of the input.
*/
"value"?: number | null;
}
interface BalPagination {
/**
* Disables component
Expand Down Expand Up @@ -3945,6 +4068,7 @@ declare namespace LocalJSX {
"bal-navbar-menu-start": BalNavbarMenuStart;
"bal-notices": BalNotices;
"bal-notification": BalNotification;
"bal-number-input": BalNumberInput;
"bal-pagination": BalPagination;
"bal-popover": BalPopover;
"bal-popover-content": BalPopoverContent;
Expand Down Expand Up @@ -4032,6 +4156,7 @@ declare module "@stencil/core" {
"bal-navbar-menu-start": LocalJSX.BalNavbarMenuStart & JSXBase.HTMLAttributes<HTMLBalNavbarMenuStartElement>;
"bal-notices": LocalJSX.BalNotices & JSXBase.HTMLAttributes<HTMLBalNoticesElement>;
"bal-notification": LocalJSX.BalNotification & JSXBase.HTMLAttributes<HTMLBalNotificationElement>;
"bal-number-input": LocalJSX.BalNumberInput & JSXBase.HTMLAttributes<HTMLBalNumberInputElement>;
"bal-pagination": LocalJSX.BalPagination & JSXBase.HTMLAttributes<HTMLBalPaginationElement>;
"bal-popover": LocalJSX.BalPopover & JSXBase.HTMLAttributes<HTMLBalPopoverElement>;
"bal-popover-content": LocalJSX.BalPopoverContent & JSXBase.HTMLAttributes<HTMLBalPopoverContentElement>;
Expand Down
30 changes: 22 additions & 8 deletions packages/components/src/components/form/bal-input/bal-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
} from '@stencil/core'
import isNil from 'lodash.isnil'
import { NUMBER_KEYS, ACTION_KEYS, isCtrlOrCommandKey } from '../../../constants/keys.constant'
import { debounceEvent, findItemLabel } from '../../../helpers/helpers'
import { filterInputValue, formatInputValue } from '../bal-number-input/bal-input.utils'
import { debounceEvent, findItemLabel, inheritAttributes } from '../../../helpers/helpers'
import { AutocompleteTypes, InputTypes } from '../../../types/interfaces'
import { getDecimalSeparator } from '../../../utils/number.util'
import { filterInputValue, formatInputValue } from './bal-input.utils'
import {
defaultConfig,
BalLanguage,
Expand All @@ -33,6 +33,7 @@ import {
export class Input implements ComponentInterface, BalConfigObserver {
private inputId = `bal-input-${InputIds++}`
private nativeInput?: HTMLInputElement
private inheritedAttributes: { [k: string]: any } = {}
private didInit = false
private hasFocus = false

Expand Down Expand Up @@ -162,12 +163,20 @@ export class Input implements ComponentInterface, BalConfigObserver {
@Prop() clickable = false

/**
* If `true` on mobile device the number keypad is active
* @deprecated
* If `true` on mobile device the number keypad is active. Use the <bal-number-input> component instead.
*/
@Prop() numberInput = false
@Watch('numberInput')
numberInputHandler() {
if (this.numberInput) {
console.warn('[DEPRECATED] - Please use the component <bal-number-input> instead')
}
}

/**
* Defines the allowed decimal points for the `number-input`.
* @deprecated
* Defines the allowed decimal points for the `number-input`. Use the <bal-number-input> component instead.
*/
@Prop() decimal?: number

Expand All @@ -192,13 +201,13 @@ export class Input implements ComponentInterface, BalConfigObserver {
/**
* The value of the input.
*/
@Prop({ mutable: true }) value?: string | number = ''
@Prop({ mutable: true }) value?: string = ''

/**
* Update the native input element when the value changes
*/
@Watch('value')
protected async valueChanged(newValue: string | number | undefined, oldValue: string | number | undefined) {
protected async valueChanged(newValue: string | undefined, oldValue: string | undefined) {
if (this.didInit && !this.hasFocus && newValue !== oldValue) {
this.balChange.emit(this.getRawValue())
}
Expand Down Expand Up @@ -254,6 +263,10 @@ export class Input implements ComponentInterface, BalConfigObserver {
}
}

componentWillLoad() {
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label', 'tabindex', 'title'])
}

disconnectedCallback() {
detachComponentToConfig(this)
}
Expand Down Expand Up @@ -290,7 +303,7 @@ export class Input implements ComponentInterface, BalConfigObserver {
}

private getRawValue(): string {
const value = typeof this.value === 'number' ? this.value.toString() : (this.value || '').toString()
const value = (this.value || '').toString()
return value
}

Expand Down Expand Up @@ -372,6 +385,7 @@ export class Input implements ComponentInterface, BalConfigObserver {
if (this.numberInput) {
inputProps = { pattern: '[0-9]*' }
}

return (
<Host
onClick={this.handleClick}
Expand Down Expand Up @@ -410,7 +424,6 @@ export class Input implements ComponentInterface, BalConfigObserver {
required={this.required}
spellcheck={this.spellcheck}
type={this.type}
tabindex={this.balTabindex}
value={value}
{...inputProps}
onInput={ev => this.onInput(ev as InputEvent)}
Expand All @@ -419,6 +432,7 @@ export class Input implements ComponentInterface, BalConfigObserver {
onFocus={this.onFocus}
onClick={this.onClick}
onKeyPress={e => this.balKeyPress.emit(e)}
{...this.inheritedAttributes}
/>
</Host>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,6 @@ TextInput.parameters = {
},
}

export const NumberInput = Template.bind({})
NumberInput.args = {
placeholder: 'Enter a number',
numberInput: true,
invalid: false,
suffix: 'CHF',
decimal: '2',
}
NumberInput.parameters = {
...component.sourceCode(NumberInput),
controls: {
exclude: excludedControls,
},
}

export const InvalidInput = Template.bind({})
InvalidInput.args = {
value: 'Value',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const filterInputValue = (
return oldValue === undefined ? '' : `${oldValue}`
}

export const formatInputValue = (value: string, decimalPoints: number | undefined = undefined): string => {
export const formatInputValue = (value: string, decimalPoints = 0): string => {
if (value.charAt(0) === getDecimalSeparator()) {
value = `0${value}`
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
bal-number-input {
display: block;
position: relative;
flex: 1;
align-items: center;
width: 100%;
padding: 0 !important;
font-family: $family-primary;
}
Loading

0 comments on commit cf6a4db

Please sign in to comment.