Set typescript to strict mode. Fixes #961

This commit is contained in:
Francisco Hodge 2021-04-04 13:28:10 -04:00
parent 42ce937f3e
commit 0d1faf61c2
6 changed files with 287 additions and 260 deletions

View File

@ -9,7 +9,7 @@ import {
class CandidateBox { class CandidateBox {
utilities: Utilities; utilities: Utilities;
candidateBoxElement: HTMLDivElement; candidateBoxElement!: HTMLDivElement;
pageIndex = 0; pageIndex = 0;
pageSize; pageSize;

View File

@ -22,28 +22,29 @@ import CandidateBox from "./CandidateBox";
* - Handles button functionality * - Handles button functionality
*/ */
class SimpleKeyboard { class SimpleKeyboard {
input: KeyboardInput; input!: KeyboardInput;
options: KeyboardOptions; options!: KeyboardOptions;
utilities: any; utilities: any;
caretPosition: number; caretPosition!: number | null;
caretPositionEnd: number; caretPositionEnd!: number | null;
keyboardDOM: KeyboardElement; keyboardDOM!: KeyboardElement;
keyboardPluginClasses: string; keyboardPluginClasses!: string;
keyboardDOMClass: string; keyboardDOMClass!: string;
buttonElements: KeyboardButtonElements; buttonElements!: KeyboardButtonElements;
currentInstanceName: string; currentInstanceName!: string;
allKeyboardInstances: { [key: string]: SimpleKeyboard }; allKeyboardInstances!: { [key: string]: SimpleKeyboard };
keyboardInstanceNames: string[]; keyboardInstanceNames!: string[];
isFirstKeyboardInstance: boolean; isFirstKeyboardInstance!: boolean;
physicalKeyboard: PhysicalKeyboard; physicalKeyboard!: PhysicalKeyboard;
modules: { [key: string]: any }; modules!: { [key: string]: any };
activeButtonClass: string; activeButtonClass!: string;
holdInteractionTimeout: number; holdInteractionTimeout!: number;
holdTimeout: number; holdTimeout!: number;
isMouseHold: boolean; isMouseHold!: boolean;
initialized: boolean; initialized!: boolean;
candidateBox: CandidateBox; candidateBox!: CandidateBox | null;
keyboardRowsDOM: KeyboardElement; keyboardRowsDOM!: KeyboardElement;
defaultName = "default";
/** /**
* Creates an instance of SimpleKeyboard * Creates an instance of SimpleKeyboard
@ -159,8 +160,9 @@ class SimpleKeyboard {
* @property {object} default Default SimpleKeyboard internal input. * @property {object} default Default SimpleKeyboard internal input.
* @property {object} myInputName Example input that can be set through `options.inputName:"myInputName"`. * @property {object} myInputName Example input that can be set through `options.inputName:"myInputName"`.
*/ */
const { inputName = this.defaultName } = this.options;
this.input = {}; this.input = {};
this.input[this.options.inputName] = ""; this.input[inputName] = "";
/** /**
* @type {string} DOM class of the keyboard wrapper, normally "simple-keyboard" by default. * @type {string} DOM class of the keyboard wrapper, normally "simple-keyboard" by default.
@ -231,7 +233,7 @@ class SimpleKeyboard {
): { ): {
keyboardDOMClass: string; keyboardDOMClass: string;
keyboardDOM: KeyboardElement; keyboardDOM: KeyboardElement;
options: Partial<KeyboardOptions>; options: Partial<KeyboardOptions | undefined>;
} => { } => {
let keyboardDOMClass; let keyboardDOMClass;
let keyboardDOM; let keyboardDOM;
@ -287,15 +289,15 @@ class SimpleKeyboard {
* Getters * Getters
*/ */
getOptions = (): KeyboardOptions => this.options; getOptions = (): KeyboardOptions => this.options;
getCaretPosition = (): number => this.caretPosition; getCaretPosition = (): number | null => this.caretPosition;
getCaretPositionEnd = (): number => this.caretPositionEnd; getCaretPositionEnd = (): number | null => this.caretPositionEnd;
/** /**
* Changes the internal caret position * Changes the internal caret position
* @param {number} position The caret's start position * @param {number} position The caret's start position
* @param {number} positionEnd The caret's end position * @param {number} positionEnd The caret's end position
*/ */
setCaretPosition(position: number, endPosition = position): void { setCaretPosition(position: number | null, endPosition = position): void {
this.caretPosition = position; this.caretPosition = position;
this.caretPositionEnd = endPosition; this.caretPositionEnd = endPosition;
} }
@ -379,8 +381,7 @@ class SimpleKeyboard {
* @param {string} button The button's layout name. * @param {string} button The button's layout name.
*/ */
handleButtonClicked(button: string, e?: KeyboardHandlerEvent): void { handleButtonClicked(button: string, e?: KeyboardHandlerEvent): void {
const debug = this.options.debug; const { inputName = this.defaultName, debug } = this.options;
/** /**
* Ignoring placeholder buttons * Ignoring placeholder buttons
*/ */
@ -389,15 +390,14 @@ class SimpleKeyboard {
/** /**
* Creating inputName if it doesn't exist * Creating inputName if it doesn't exist
*/ */
if (!this.input[this.options.inputName]) if (!this.input[inputName]) this.input[inputName] = "";
this.input[this.options.inputName] = "";
/** /**
* Calculating new input * Calculating new input
*/ */
const updatedInput = this.utilities.getUpdatedInput( const updatedInput = this.utilities.getUpdatedInput(
button, button,
this.input[this.options.inputName], this.input[inputName],
this.caretPosition, this.caretPosition,
this.caretPositionEnd this.caretPositionEnd
); );
@ -410,7 +410,7 @@ class SimpleKeyboard {
if ( if (
// If input will change as a result of this button press // If input will change as a result of this button press
this.input[this.options.inputName] !== updatedInput && this.input[inputName] !== updatedInput &&
// This pertains to the "inputPattern" option: // This pertains to the "inputPattern" option:
// If inputPattern isn't set // If inputPattern isn't set
(!this.options.inputPattern || (!this.options.inputPattern ||
@ -432,7 +432,7 @@ class SimpleKeyboard {
*/ */
const newInputValue = this.utilities.getUpdatedInput( const newInputValue = this.utilities.getUpdatedInput(
button, button,
this.input[this.options.inputName], this.input[inputName],
this.caretPosition, this.caretPosition,
this.caretPositionEnd, this.caretPositionEnd,
true true
@ -483,7 +483,7 @@ class SimpleKeyboard {
this.keyboardDOM this.keyboardDOM
); );
} else { } else {
this.candidateBox.destroy(); this.candidateBox?.destroy();
} }
} }
} }
@ -639,7 +639,9 @@ class SimpleKeyboard {
* Clear the keyboards input. * Clear the keyboards input.
* @param {string} [inputName] optional - the internal input to select * @param {string} [inputName] optional - the internal input to select
*/ */
clearInput(inputName = this.options.inputName): void { clearInput(
inputName: string = this.options.inputName || this.defaultName
): void {
this.input[inputName] = ""; this.input[inputName] = "";
/** /**
@ -657,7 +659,10 @@ class SimpleKeyboard {
* Get the keyboards input (You can also get it from the onChange prop). * Get the keyboards input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select * @param {string} [inputName] optional - the internal input to select
*/ */
getInput(inputName = this.options.inputName, skipSync = false): string { getInput(
inputName: string = this.options.inputName || this.defaultName,
skipSync = false
): string {
/** /**
* Enforce syncInstanceInputs, if set * Enforce syncInstanceInputs, if set
*/ */
@ -696,7 +701,7 @@ class SimpleKeyboard {
*/ */
setInput( setInput(
input: string, input: string,
inputName = this.options.inputName, inputName: string = this.options.inputName || this.defaultName,
skipSync?: boolean skipSync?: boolean
): void { ): void {
this.input[inputName] = input; this.input[inputName] = input;
@ -850,7 +855,7 @@ class SimpleKeyboard {
* If class is already defined, we add button to class definition * If class is already defined, we add button to class definition
*/ */
this.options.buttonTheme.map((buttonTheme) => { this.options.buttonTheme.map((buttonTheme) => {
if (buttonTheme.class.split(" ").includes(classNameItem)) { if (buttonTheme?.class.split(" ").includes(classNameItem)) {
classNameFound = true; classNameFound = true;
const buttonThemeArray = buttonTheme.buttons.split(" "); const buttonThemeArray = buttonTheme.buttons.split(" ");
@ -903,26 +908,28 @@ class SimpleKeyboard {
) { ) {
const buttonArray = buttons.split(" "); const buttonArray = buttons.split(" ");
buttonArray.forEach((button) => { buttonArray.forEach((button) => {
this.options.buttonTheme.map((buttonTheme, index) => { this.options?.buttonTheme?.map((buttonTheme, index) => {
/** /**
* If className is set, we affect the buttons only for that class * If className is set, we affect the buttons only for that class
* Otherwise, we afect all classes * Otherwise, we afect all classes
*/ */
if ( if (
(className && className.includes(buttonTheme.class)) || (buttonTheme &&
className &&
className.includes(buttonTheme.class)) ||
!className !className
) { ) {
const filteredButtonArray = buttonTheme.buttons const filteredButtonArray = buttonTheme?.buttons
.split(" ") .split(" ")
.filter((item) => item !== button); .filter((item) => item !== button);
/** /**
* If buttons left, return them, otherwise, remove button Theme * If buttons left, return them, otherwise, remove button Theme
*/ */
if (filteredButtonArray.length) { if (buttonTheme && filteredButtonArray?.length) {
buttonTheme.buttons = filteredButtonArray.join(" "); buttonTheme.buttons = filteredButtonArray.join(" ");
} else { } else {
this.options.buttonTheme.splice(index, 1); this.options.buttonTheme?.splice(index, 1);
buttonTheme = null; buttonTheme = null;
} }
} }
@ -939,7 +946,9 @@ class SimpleKeyboard {
* Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned. * Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned.
* @param {string} button The button layout name to select * @param {string} button The button layout name to select
*/ */
getButtonElement(button: string): KeyboardElement | KeyboardElement[] { getButtonElement(
button: string
): KeyboardElement | KeyboardElement[] | undefined {
let output; let output;
const buttonArr = this.buttonElements[button]; const buttonArr = this.buttonElements[button];
@ -968,7 +977,8 @@ class SimpleKeyboard {
if (inputPatternRaw instanceof RegExp) { if (inputPatternRaw instanceof RegExp) {
inputPattern = inputPatternRaw; inputPattern = inputPatternRaw;
} else { } else {
inputPattern = inputPatternRaw[this.options.inputName]; inputPattern =
inputPatternRaw[this.options.inputName || this.defaultName];
} }
if (inputPattern && inputVal) { if (inputPattern && inputVal) {
@ -1146,26 +1156,25 @@ class SimpleKeyboard {
/** /**
* Remove buttons * Remove buttons
*/ */
let deleteButton = (buttonElement: KeyboardElement) => { const deleteButton = (buttonElement: KeyboardElement | null) => {
buttonElement.onpointerdown = null; if (buttonElement) {
buttonElement.onpointerup = null; buttonElement.onpointerdown = null;
buttonElement.onpointercancel = null; buttonElement.onpointerup = null;
buttonElement.ontouchstart = null; buttonElement.onpointercancel = null;
buttonElement.ontouchend = null; buttonElement.ontouchstart = null;
buttonElement.ontouchcancel = null; buttonElement.ontouchend = null;
buttonElement.onclick = null; buttonElement.ontouchcancel = null;
buttonElement.onmousedown = null; buttonElement.onclick = null;
buttonElement.onmouseup = null; buttonElement.onmousedown = null;
buttonElement.onmouseup = null;
buttonElement.remove(); buttonElement.remove();
buttonElement = null; buttonElement = null;
}
}; };
this.recurseButtons(deleteButton); this.recurseButtons(deleteButton);
this.recurseButtons = null;
deleteButton = null;
/** /**
* Remove wrapper events * Remove wrapper events
*/ */
@ -1213,6 +1222,7 @@ class SimpleKeyboard {
if (Array.isArray(buttonTheme)) { if (Array.isArray(buttonTheme)) {
buttonTheme.forEach((themeObj) => { buttonTheme.forEach((themeObj) => {
if ( if (
themeObj &&
themeObj.class && themeObj.class &&
typeof themeObj.class === "string" && typeof themeObj.class === "string" &&
themeObj.buttons && themeObj.buttons &&
@ -1574,211 +1584,219 @@ class SimpleKeyboard {
/** /**
* Iterating through each row * Iterating through each row
*/ */
layout[this.options.layoutName].forEach((row, rIndex) => { layout[this.options.layoutName || this.defaultName].forEach(
let rowArray = row.split(" "); (row, rIndex) => {
let rowArray = row.split(" ");
/**
* Enforce excludeFromLayout
*/
if (this.options.excludeFromLayout[this.options.layoutName]) {
rowArray = rowArray.filter(
(buttonName) =>
!this.options.excludeFromLayout[this.options.layoutName].includes(
buttonName
)
);
}
/**
* Creating empty row
*/
let rowDOM = document.createElement("div");
rowDOM.className += "hg-row";
/**
* Tracking container indicators in rows
*/
const containerStartIndexes: number[] = [];
const containerEndIndexes: number[] = [];
/**
* Iterating through each button in row
*/
rowArray.forEach((button, bIndex) => {
/**
* Check if button has a container indicator
*/
const buttonHasContainerStart =
!disableRowButtonContainers &&
typeof button === "string" &&
button.length > 1 &&
button.indexOf("[") === 0;
const buttonHasContainerEnd =
!disableRowButtonContainers &&
typeof button === "string" &&
button.length > 1 &&
button.indexOf("]") === button.length - 1;
/** /**
* Save container start index, if applicable * Enforce excludeFromLayout
*/ */
if (buttonHasContainerStart) {
containerStartIndexes.push(bIndex);
/**
* Removing indicator
*/
button = button.replace(/\[/g, "");
}
if (buttonHasContainerEnd) {
containerEndIndexes.push(bIndex);
/**
* Removing indicator
*/
button = button.replace(/\]/g, "");
}
/**
* Processing button options
*/
const fctBtnClass = this.utilities.getButtonClass(button);
const buttonDisplayName = this.utilities.getButtonDisplayName(
button,
this.options.display,
this.options.mergeDisplay
);
/**
* Creating button
*/
const buttonType = this.options.useButtonTag ? "button" : "div";
const buttonDOM = document.createElement(buttonType);
buttonDOM.className += `hg-button ${fctBtnClass}`;
/**
* Adding buttonTheme
*/
buttonDOM.classList.add(...this.getButtonThemeClasses(button));
/**
* Adding buttonAttributes
*/
this.setDOMButtonAttributes(
button,
(attribute: string, value: string) => {
buttonDOM.setAttribute(attribute, value);
}
);
this.activeButtonClass = "hg-activeButton";
/**
* Handle button click event
*/
/* istanbul ignore next */
if ( if (
this.utilities.pointerEventsSupported() && this.options.excludeFromLayout &&
!useTouchEvents && this.options.excludeFromLayout[
!useMouseEvents this.options.layoutName || this.defaultName
]
) { ) {
rowArray = rowArray.filter(
(buttonName) =>
this.options.excludeFromLayout &&
!this.options.excludeFromLayout[
this.options.layoutName || this.defaultName
].includes(buttonName)
);
}
/**
* Creating empty row
*/
let rowDOM = document.createElement("div");
rowDOM.className += "hg-row";
/**
* Tracking container indicators in rows
*/
const containerStartIndexes: number[] = [];
const containerEndIndexes: number[] = [];
/**
* Iterating through each button in row
*/
rowArray.forEach((button, bIndex) => {
/** /**
* Handle PointerEvents * Check if button has a container indicator
*/ */
buttonDOM.onpointerdown = (e: KeyboardHandlerEvent) => { const buttonHasContainerStart =
this.handleButtonClicked(button, e); !disableRowButtonContainers &&
this.handleButtonMouseDown(button, e); typeof button === "string" &&
}; button.length > 1 &&
buttonDOM.onpointerup = (e: KeyboardHandlerEvent) => { button.indexOf("[") === 0;
this.handleButtonMouseUp(button, e);
}; const buttonHasContainerEnd =
buttonDOM.onpointercancel = (e: KeyboardHandlerEvent) => { !disableRowButtonContainers &&
this.handleButtonMouseUp(button, e); typeof button === "string" &&
}; button.length > 1 &&
} else { button.indexOf("]") === button.length - 1;
/** /**
* Fallback for browsers not supporting PointerEvents * Save container start index, if applicable
*/ */
if (useTouchEvents) { if (buttonHasContainerStart) {
containerStartIndexes.push(bIndex);
/** /**
* Handle touch events * Removing indicator
*/ */
buttonDOM.ontouchstart = (e: KeyboardHandlerEvent) => { button = button.replace(/\[/g, "");
}
if (buttonHasContainerEnd) {
containerEndIndexes.push(bIndex);
/**
* Removing indicator
*/
button = button.replace(/\]/g, "");
}
/**
* Processing button options
*/
const fctBtnClass = this.utilities.getButtonClass(button);
const buttonDisplayName = this.utilities.getButtonDisplayName(
button,
this.options.display,
this.options.mergeDisplay
);
/**
* Creating button
*/
const buttonType = this.options.useButtonTag ? "button" : "div";
const buttonDOM = document.createElement(buttonType);
buttonDOM.className += `hg-button ${fctBtnClass}`;
/**
* Adding buttonTheme
*/
buttonDOM.classList.add(...this.getButtonThemeClasses(button));
/**
* Adding buttonAttributes
*/
this.setDOMButtonAttributes(
button,
(attribute: string, value: string) => {
buttonDOM.setAttribute(attribute, value);
}
);
this.activeButtonClass = "hg-activeButton";
/**
* Handle button click event
*/
/* istanbul ignore next */
if (
this.utilities.pointerEventsSupported() &&
!useTouchEvents &&
!useMouseEvents
) {
/**
* Handle PointerEvents
*/
buttonDOM.onpointerdown = (e: KeyboardHandlerEvent) => {
this.handleButtonClicked(button, e); this.handleButtonClicked(button, e);
this.handleButtonMouseDown(button, e); this.handleButtonMouseDown(button, e);
}; };
buttonDOM.ontouchend = (e: KeyboardHandlerEvent) => { buttonDOM.onpointerup = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseUp(button, e); this.handleButtonMouseUp(button, e);
}; };
buttonDOM.ontouchcancel = (e: KeyboardHandlerEvent) => { buttonDOM.onpointercancel = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseUp(button, e); this.handleButtonMouseUp(button, e);
}; };
} else { } else {
/** /**
* Handle mouse events * Fallback for browsers not supporting PointerEvents
*/ */
buttonDOM.onclick = (e: KeyboardHandlerEvent) => { if (useTouchEvents) {
this.isMouseHold = false; /**
this.handleButtonClicked(button, e); * Handle touch events
}; */
buttonDOM.onmousedown = (e: KeyboardHandlerEvent) => { buttonDOM.ontouchstart = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseDown(button, e); this.handleButtonClicked(button, e);
}; this.handleButtonMouseDown(button, e);
buttonDOM.onmouseup = (e: KeyboardHandlerEvent) => { };
this.handleButtonMouseUp(button, e); buttonDOM.ontouchend = (e: KeyboardHandlerEvent) => {
}; this.handleButtonMouseUp(button, e);
};
buttonDOM.ontouchcancel = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseUp(button, e);
};
} else {
/**
* Handle mouse events
*/
buttonDOM.onclick = (e: KeyboardHandlerEvent) => {
this.isMouseHold = false;
this.handleButtonClicked(button, e);
};
buttonDOM.onmousedown = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseDown(button, e);
};
buttonDOM.onmouseup = (e: KeyboardHandlerEvent) => {
this.handleButtonMouseUp(button, e);
};
}
} }
}
/**
* Adding identifier
*/
buttonDOM.setAttribute("data-skBtn", button);
/**
* Adding unique id
* Since there's no limit on spawning same buttons, the unique id ensures you can style every button
*/
const buttonUID = `${this.options.layoutName}-r${rIndex}b${bIndex}`;
buttonDOM.setAttribute("data-skBtnUID", buttonUID);
/**
* Adding button label to button
*/
const buttonSpanDOM = document.createElement("span");
buttonSpanDOM.innerHTML = buttonDisplayName;
buttonDOM.appendChild(buttonSpanDOM);
/**
* Adding to buttonElements
*/
if (!this.buttonElements[button]) this.buttonElements[button] = [];
this.buttonElements[button].push(buttonDOM);
/**
* Appending button to row
*/
rowDOM.appendChild(buttonDOM);
});
/** /**
* Adding identifier * Parse containers in row
*/ */
buttonDOM.setAttribute("data-skBtn", button); rowDOM = this.parseRowDOMContainers(
rowDOM,
rIndex,
containerStartIndexes,
containerEndIndexes
);
/** /**
* Adding unique id * Appending row to hg-rows
* Since there's no limit on spawning same buttons, the unique id ensures you can style every button
*/ */
const buttonUID = `${this.options.layoutName}-r${rIndex}b${bIndex}`; this.keyboardRowsDOM.appendChild(rowDOM);
buttonDOM.setAttribute("data-skBtnUID", buttonUID); }
);
/**
* Adding button label to button
*/
const buttonSpanDOM = document.createElement("span");
buttonSpanDOM.innerHTML = buttonDisplayName;
buttonDOM.appendChild(buttonSpanDOM);
/**
* Adding to buttonElements
*/
if (!this.buttonElements[button]) this.buttonElements[button] = [];
this.buttonElements[button].push(buttonDOM);
/**
* Appending button to row
*/
rowDOM.appendChild(buttonDOM);
});
/**
* Parse containers in row
*/
rowDOM = this.parseRowDOMContainers(
rowDOM,
rIndex,
containerStartIndexes,
containerEndIndexes
);
/**
* Appending row to hg-rows
*/
this.keyboardRowsDOM.appendChild(rowDOM);
});
/** /**
* Appending row to keyboard * Appending row to keyboard
@ -1806,7 +1824,7 @@ class SimpleKeyboard {
!useMouseEvents !useMouseEvents
) { ) {
document.onpointerup = (e: KeyboardHandlerEvent) => document.onpointerup = (e: KeyboardHandlerEvent) =>
this.handleButtonMouseUp(null, e); this.handleButtonMouseUp(undefined, e);
this.keyboardDOM.onpointerdown = (e: KeyboardHandlerEvent) => this.keyboardDOM.onpointerdown = (e: KeyboardHandlerEvent) =>
this.handleKeyboardContainerMouseDown(e); this.handleKeyboardContainerMouseDown(e);
} else if (useTouchEvents) { } else if (useTouchEvents) {
@ -1814,9 +1832,9 @@ class SimpleKeyboard {
* Handling ontouchend, ontouchcancel * Handling ontouchend, ontouchcancel
*/ */
document.ontouchend = (e: KeyboardHandlerEvent) => document.ontouchend = (e: KeyboardHandlerEvent) =>
this.handleButtonMouseUp(null, e); this.handleButtonMouseUp(undefined, e);
document.ontouchcancel = (e: KeyboardHandlerEvent) => document.ontouchcancel = (e: KeyboardHandlerEvent) =>
this.handleButtonMouseUp(null, e); this.handleButtonMouseUp(undefined, e);
this.keyboardDOM.ontouchstart = (e: KeyboardHandlerEvent) => this.keyboardDOM.ontouchstart = (e: KeyboardHandlerEvent) =>
this.handleKeyboardContainerMouseDown(e); this.handleKeyboardContainerMouseDown(e);
@ -1825,7 +1843,7 @@ class SimpleKeyboard {
* Handling mouseup * Handling mouseup
*/ */
document.onmouseup = (e: KeyboardHandlerEvent) => document.onmouseup = (e: KeyboardHandlerEvent) =>
this.handleButtonMouseUp(null, e); this.handleButtonMouseUp(undefined, e);
this.keyboardDOM.onmousedown = (e: KeyboardHandlerEvent) => this.keyboardDOM.onmousedown = (e: KeyboardHandlerEvent) =>
this.handleKeyboardContainerMouseDown(e); this.handleKeyboardContainerMouseDown(e);
} }

View File

@ -6,10 +6,10 @@ export interface KeyboardLayoutObject {
[key: string]: string[]; [key: string]: string[];
} }
export interface KeyboardButtonTheme { export type KeyboardButtonTheme = {
class: string; class: string;
buttons: string; buttons: string;
} } | null;
export interface KeyboardButtonAttributes { export interface KeyboardButtonAttributes {
attribute: string; attribute: string;
@ -44,7 +44,7 @@ export type CandidateBoxRenderParams = {
} }
export type KeyboardElement = HTMLDivElement | HTMLButtonElement; export type KeyboardElement = HTMLDivElement | HTMLButtonElement;
export type KeyboardHandlerEvent = PointerEvent & TouchEvent & KeyboardEvent & { target: HTMLDivElement & HTMLInputElement }; export type KeyboardHandlerEvent = any;
export interface KeyboardButtonElements { export interface KeyboardButtonElements {
[key: string]: KeyboardElement[] [key: string]: KeyboardElement[]
@ -52,8 +52,13 @@ export interface KeyboardButtonElements {
export interface UtilitiesParams { export interface UtilitiesParams {
getOptions: () => KeyboardOptions; getOptions: () => KeyboardOptions;
getCaretPosition: () => number; getCaretPosition: () => number | null;
getCaretPositionEnd: () => number; getCaretPositionEnd: () => number | null;
dispatch: any;
}
export interface PhysicalKeyboardParams {
getOptions: () => KeyboardOptions;
dispatch: any; dispatch: any;
} }

View File

@ -1,4 +1,4 @@
import { KeyboardOptions, UtilitiesParams } from "../interfaces"; import { KeyboardOptions, PhysicalKeyboardParams } from "../interfaces";
import Utilities from "../services/Utilities"; import Utilities from "../services/Utilities";
/** /**
@ -11,7 +11,7 @@ class PhysicalKeyboard {
/** /**
* Creates an instance of the PhysicalKeyboard service * Creates an instance of the PhysicalKeyboard service
*/ */
constructor({ dispatch, getOptions }: Partial<UtilitiesParams>) { constructor({ dispatch, getOptions }: PhysicalKeyboardParams) {
/** /**
* @type {object} A simple-keyboard instance * @type {object} A simple-keyboard instance
*/ */

View File

@ -6,10 +6,10 @@ import { KeyboardOptions, UtilitiesParams } from "../interfaces";
*/ */
class Utilities { class Utilities {
getOptions: () => KeyboardOptions; getOptions: () => KeyboardOptions;
getCaretPosition: () => number; getCaretPosition: () => number | null;
getCaretPositionEnd: () => number; getCaretPositionEnd: () => number | null;
dispatch: any; dispatch: any;
maxLengthReached: boolean; maxLengthReached!: boolean;
/** /**
* Creates an instance of the Utility service * Creates an instance of the Utility service
@ -243,10 +243,12 @@ class Utilities {
const options = this.getOptions(); const options = this.getOptions();
let caretPosition = this.getCaretPosition(); let caretPosition = this.getCaretPosition();
if (minus) { if (caretPosition != null) {
if (caretPosition > 0) caretPosition = caretPosition - length; if (minus) {
} else { if (caretPosition > 0) caretPosition = caretPosition - length;
caretPosition = caretPosition + length; } else {
caretPosition = caretPosition + length;
}
} }
if (options.debug) { if (options.debug) {
@ -362,7 +364,7 @@ class Utilities {
handleMaxLength(inputObj: KeyboardInput, updatedInput: string) { handleMaxLength(inputObj: KeyboardInput, updatedInput: string) {
const options = this.getOptions(); const options = this.getOptions();
const maxLength = options.maxLength; const maxLength = options.maxLength;
const currentInput = inputObj[options.inputName]; const currentInput = inputObj[options.inputName || "default"];
const condition = updatedInput.length - 1 >= maxLength; const condition = updatedInput.length - 1 >= maxLength;
if ( if (
@ -393,7 +395,8 @@ class Utilities {
} }
if (typeof maxLength === "object") { if (typeof maxLength === "object") {
const condition = updatedInput.length - 1 >= maxLength[options.inputName]; const condition =
updatedInput.length - 1 >= maxLength[options.inputName || "default"];
if (options.debug) { if (options.debug) {
console.log("maxLength (obj) reached:", condition); console.log("maxLength (obj) reached:", condition);
@ -451,7 +454,7 @@ class Utilities {
* @param {string} str The string to transform. * @param {string} str The string to transform.
*/ */
camelCase(str: string): string { camelCase(str: string): string {
if (!str) return; if (!str) return "";
return str return str
.toLowerCase() .toLowerCase()

View File

@ -11,7 +11,8 @@
"suppressImplicitAnyIndexErrors": true, "suppressImplicitAnyIndexErrors": true,
"lib": ["es2020", "dom"], "lib": ["es2020", "dom"],
"moduleResolution": "node", "moduleResolution": "node",
"downlevelIteration": true "downlevelIteration": true,
"strict": true
}, },
"include": ["src/lib"], "include": ["src/lib"],
"exclude": ["src/lib/**/tests"], "exclude": ["src/lib/**/tests"],