import { css, html } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { ClassInfo, classMap } from 'lit/directives/class-map.js';
import { live } from 'lit/directives/live.js';
import { ifDefined, OmniFormElement } from '../core/OmniFormElement.js';
/**
* Input control to enter a single line of numbers.
*
* @import
* ```js
* import '@capitec/omni-components/number-field';
* ```
* @example
* ```html
*
*
* ```
*
* @element omni-number-field
*
* @cssprop --omni-number-field-text-align - Number field text align.
* @cssprop --omni-number-field-font-color - Number field font color.
* @cssprop --omni-number-field-font-family - Number field font family.
* @cssprop --omni-number-field-font-size - Number field font size.
* @cssprop --omni-number-field-font-weight - Number field font weight.
* @cssprop --omni-number-field-padding - Number field padding.
* @cssprop --omni-number-field-height - Number field height.
* @cssprop --omni-number-field-width - Number field width.
*
* @cssprop --omni-number-field-disabled-font-color - Number field disabled font color.
* @cssprop --omni-number-field-error-font-color - Number field error font color.
*
* @cssprop --omni-number-field-autofill-hover-transition - Number field suggestions input hover color.
*/
@customElement('omni-number-field')
export class NumberField extends OmniFormElement {
@query('#inputField')
private _inputElement?: HTMLInputElement;
/**
* Disables native on screen keyboards for the component.
* @attr [no-native-keyboard]
*/
@property({ type: Boolean, reflect: true, attribute: 'no-native-keyboard' }) noNativeKeyboard?: boolean;
/**
* Maximum character input length.
* @attr [max-length]
*/
@property({ type: Number, reflect: true, attribute: 'max-length' }) maxLength?: number;
override connectedCallback() {
super.connectedCallback();
this.addEventListener('input', this._keyInput.bind(this), {
capture: true
});
this.addEventListener('keydown', this._keyDown.bind(this), {
capture: true
});
}
// If a value is bound when the component is first updated slice the value based on the max length if set.
protected override async firstUpdated(): Promise {
if (this.value !== null && this.value !== undefined) {
if (this.maxLength) {
this._inputElement!.value = String(this.value).slice(0, this.maxLength);
}
}
}
// Added for browsers that allow text values entered into a input when type is set to number.
override async attributeChangedCallback(name: string, _old: string | null, value: string | null): Promise {
super.attributeChangedCallback(name, _old, value);
if (name === 'value') {
if (new RegExp('^[0-9]+$').test(value as string) === false) {
return;
}
}
}
override focus(options?: FocusOptions | undefined): void {
if (this._inputElement) {
this._inputElement.focus(options);
} else {
super.focus(options);
}
}
_keyDown(e: KeyboardEvent) {
// Stop alpha keys
if (e.key >= 'a' && e.key <= 'z') {
e.preventDefault();
return;
}
}
_keyInput() {
const input = this._inputElement as HTMLInputElement;
// If the input has a value and the max length property is set then slice the value according to the max length.
if (input?.value && this.maxLength) {
if (input.value.length > this.maxLength) {
input.value = input.value.slice(0, this.maxLength);
}
}
this.value = input?.value;
}
static override get styles() {
return [
super.styles,
css`
.field {
flex: 1 1 auto;
border: none;
background: none;
box-shadow: none;
outline: 0;
padding: 0;
margin: 0;
text-align: var(--omni-number-field-text-align, left);
color: var(--omni-number-field-font-color, var(--omni-font-color));
font-family: var(--omni-number-field-font-family, var(--omni-font-family));
font-size: var(--omni-number-field-font-size, var(--omni-font-size));
font-weight: var(--omni-number-field-font-weight, var(--omni-font-weight));
padding: var(--omni-number-field-padding, 10px);
height: var(--omni-number-field-height, 100%);
width: var(--omni-number-field-width, 100%);
}
.field.disabled {
color: var(--omni-number-field-disabled-font-color, #7C7C7C);
}
.field.error {
color: var(--omni-number-field-error-font-color, var(--omni-font-color));
}
/* Used to not display default stepper */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
/* display: none; <- Crashes Chrome on hover */
-webkit-appearance: none;
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
}
input[type='number'] {
-moz-appearance: textfield; /* Firefox */
}
/* Grant the ability to set the hover color when cursor hovers over auto selectable options */
input:-webkit-autofill,
input:-webkit-autofill:focus {
transition: var(--omni-number-field-autofill-hover-transition) !important;
}
`
];
}
protected override renderContent() {
const field: ClassInfo = {
field: true,
disabled: this.disabled,
error: this.error as string
};
return html`
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'omni-number-field': NumberField;
}
}