@keenthemes/ktui 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ktui.js +2216 -845
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +24 -197
- package/lib/cjs/components/carousel/carousel.d.ts +102 -0
- package/lib/cjs/components/carousel/carousel.d.ts.map +1 -0
- package/lib/cjs/components/carousel/carousel.js +769 -0
- package/lib/cjs/components/carousel/carousel.js.map +1 -0
- package/lib/cjs/components/carousel/index.d.ts +7 -0
- package/lib/cjs/components/carousel/index.d.ts.map +1 -0
- package/lib/cjs/components/carousel/index.js +10 -0
- package/lib/cjs/components/carousel/index.js.map +1 -0
- package/lib/cjs/components/carousel/types.d.ts +36 -0
- package/lib/cjs/components/carousel/types.d.ts.map +1 -0
- package/lib/cjs/components/carousel/types.js +7 -0
- package/lib/cjs/components/carousel/types.js.map +1 -0
- package/lib/cjs/components/component.d.ts +3 -3
- package/lib/cjs/components/component.d.ts.map +1 -1
- package/lib/cjs/components/component.js +9 -1
- package/lib/cjs/components/component.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.d.ts +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.js +1 -1
- package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-sort.d.ts +1 -1
- package/lib/cjs/components/datatable/datatable-sort.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.d.ts +2 -0
- package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +30 -17
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/datatable/types.d.ts +2 -1
- package/lib/cjs/components/datatable/types.d.ts.map +1 -1
- package/lib/cjs/components/drawer/drawer.d.ts.map +1 -1
- package/lib/cjs/components/drawer/drawer.js +3 -16
- package/lib/cjs/components/drawer/drawer.js.map +1 -1
- package/lib/cjs/components/dropdown/dropdown.d.ts +1 -1
- package/lib/cjs/components/dropdown/dropdown.d.ts.map +1 -1
- package/lib/cjs/components/dropdown/dropdown.js +2 -3
- package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
- package/lib/cjs/components/modal/modal.d.ts.map +1 -1
- package/lib/cjs/components/modal/modal.js +19 -13
- package/lib/cjs/components/modal/modal.js.map +1 -1
- package/lib/cjs/components/pin-input/index.d.ts +3 -0
- package/lib/cjs/components/pin-input/index.d.ts.map +1 -0
- package/lib/cjs/components/pin-input/index.js +6 -0
- package/lib/cjs/components/pin-input/index.js.map +1 -0
- package/lib/cjs/components/pin-input/pin-input.d.ts +56 -0
- package/lib/cjs/components/pin-input/pin-input.d.ts.map +1 -0
- package/lib/cjs/components/pin-input/pin-input.js +455 -0
- package/lib/cjs/components/pin-input/pin-input.js.map +1 -0
- package/lib/cjs/components/pin-input/types.d.ts +41 -0
- package/lib/cjs/components/pin-input/types.d.ts.map +1 -0
- package/lib/cjs/components/pin-input/types.js +6 -0
- package/lib/cjs/components/pin-input/types.js.map +1 -0
- package/lib/cjs/components/rating/rating.d.ts.map +1 -1
- package/lib/cjs/components/rating/rating.js.map +1 -1
- package/lib/cjs/components/select/combobox.d.ts.map +1 -1
- package/lib/cjs/components/select/combobox.js +25 -15
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/config.d.ts +2 -2
- package/lib/cjs/components/select/config.d.ts.map +1 -1
- package/lib/cjs/components/select/config.js +10 -9
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/option.d.ts +2 -1
- package/lib/cjs/components/select/option.d.ts.map +1 -1
- package/lib/cjs/components/select/option.js +9 -3
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/remote.d.ts +1 -0
- package/lib/cjs/components/select/remote.d.ts.map +1 -1
- package/lib/cjs/components/select/remote.js +21 -14
- package/lib/cjs/components/select/remote.js.map +1 -1
- package/lib/cjs/components/select/search.d.ts +1 -1
- package/lib/cjs/components/select/search.d.ts.map +1 -1
- package/lib/cjs/components/select/search.js +34 -25
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.d.ts +5 -3
- package/lib/cjs/components/select/select.d.ts.map +1 -1
- package/lib/cjs/components/select/select.js +31 -31
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.d.ts.map +1 -1
- package/lib/cjs/components/select/tags.js +22 -13
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.d.ts.map +1 -1
- package/lib/cjs/components/select/templates.js +4 -4
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/types.d.ts +1 -1
- package/lib/cjs/components/select/types.d.ts.map +1 -1
- package/lib/cjs/components/select/utils.d.ts +4 -4
- package/lib/cjs/components/select/utils.d.ts.map +1 -1
- package/lib/cjs/components/select/utils.js +2 -3
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/components/sticky/sticky.d.ts +1 -1
- package/lib/cjs/components/sticky/sticky.d.ts.map +1 -1
- package/lib/cjs/components/sticky/sticky.js +13 -13
- package/lib/cjs/components/sticky/sticky.js.map +1 -1
- package/lib/cjs/components/theme-switch/theme-switch.d.ts +3 -0
- package/lib/cjs/components/theme-switch/theme-switch.d.ts.map +1 -1
- package/lib/cjs/components/theme-switch/theme-switch.js +17 -4
- package/lib/cjs/components/theme-switch/theme-switch.js.map +1 -1
- package/lib/cjs/components/toast/toast.d.ts.map +1 -1
- package/lib/cjs/components/toast/toast.js +17 -9
- package/lib/cjs/components/toast/toast.js.map +1 -1
- package/lib/cjs/components/toast/types.d.ts +3 -0
- package/lib/cjs/components/toast/types.d.ts.map +1 -1
- package/lib/cjs/components/toggle/toggle.d.ts +2 -0
- package/lib/cjs/components/toggle/toggle.d.ts.map +1 -1
- package/lib/cjs/components/toggle/toggle.js +11 -2
- package/lib/cjs/components/toggle/toggle.js.map +1 -1
- package/lib/cjs/components/toggle-password/toggle-password.d.ts.map +1 -1
- package/lib/cjs/components/toggle-password/toggle-password.js.map +1 -1
- package/lib/cjs/helpers/dom.d.ts +4 -4
- package/lib/cjs/helpers/dom.d.ts.map +1 -1
- package/lib/cjs/helpers/dom.js +8 -10
- package/lib/cjs/helpers/dom.js.map +1 -1
- package/lib/cjs/helpers/event-handler.d.ts +1 -1
- package/lib/cjs/helpers/event-handler.d.ts.map +1 -1
- package/lib/cjs/helpers/event-handler.js +3 -1
- package/lib/cjs/helpers/event-handler.js.map +1 -1
- package/lib/cjs/helpers/utils.d.ts +1 -1
- package/lib/cjs/helpers/utils.d.ts.map +1 -1
- package/lib/cjs/helpers/utils.js +4 -1
- package/lib/cjs/helpers/utils.js.map +1 -1
- package/lib/cjs/index.d.ts +8 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +9 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/types.d.ts +1 -1
- package/lib/cjs/types.d.ts.map +1 -1
- package/lib/esm/components/carousel/carousel.d.ts +102 -0
- package/lib/esm/components/carousel/carousel.d.ts.map +1 -0
- package/lib/esm/components/carousel/carousel.js +766 -0
- package/lib/esm/components/carousel/carousel.js.map +1 -0
- package/lib/esm/components/carousel/index.d.ts +7 -0
- package/lib/esm/components/carousel/index.d.ts.map +1 -0
- package/lib/esm/components/carousel/index.js +6 -0
- package/lib/esm/components/carousel/index.js.map +1 -0
- package/lib/esm/components/carousel/types.d.ts +36 -0
- package/lib/esm/components/carousel/types.d.ts.map +1 -0
- package/lib/esm/components/carousel/types.js +6 -0
- package/lib/esm/components/carousel/types.js.map +1 -0
- package/lib/esm/components/component.d.ts +3 -3
- package/lib/esm/components/component.d.ts.map +1 -1
- package/lib/esm/components/component.js +9 -1
- package/lib/esm/components/component.js.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.d.ts +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.js +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/esm/components/datatable/datatable-sort.d.ts +1 -1
- package/lib/esm/components/datatable/datatable-sort.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
- package/lib/esm/components/datatable/datatable.d.ts +2 -0
- package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable.js +30 -17
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/datatable/types.d.ts +2 -1
- package/lib/esm/components/datatable/types.d.ts.map +1 -1
- package/lib/esm/components/drawer/drawer.d.ts.map +1 -1
- package/lib/esm/components/drawer/drawer.js +3 -16
- package/lib/esm/components/drawer/drawer.js.map +1 -1
- package/lib/esm/components/dropdown/dropdown.d.ts +1 -1
- package/lib/esm/components/dropdown/dropdown.d.ts.map +1 -1
- package/lib/esm/components/dropdown/dropdown.js +2 -3
- package/lib/esm/components/dropdown/dropdown.js.map +1 -1
- package/lib/esm/components/modal/modal.d.ts.map +1 -1
- package/lib/esm/components/modal/modal.js +19 -13
- package/lib/esm/components/modal/modal.js.map +1 -1
- package/lib/esm/components/pin-input/index.d.ts +3 -0
- package/lib/esm/components/pin-input/index.d.ts.map +1 -0
- package/lib/esm/components/pin-input/index.js +2 -0
- package/lib/esm/components/pin-input/index.js.map +1 -0
- package/lib/esm/components/pin-input/pin-input.d.ts +56 -0
- package/lib/esm/components/pin-input/pin-input.d.ts.map +1 -0
- package/lib/esm/components/pin-input/pin-input.js +452 -0
- package/lib/esm/components/pin-input/pin-input.js.map +1 -0
- package/lib/esm/components/pin-input/types.d.ts +41 -0
- package/lib/esm/components/pin-input/types.d.ts.map +1 -0
- package/lib/esm/components/pin-input/types.js +5 -0
- package/lib/esm/components/pin-input/types.js.map +1 -0
- package/lib/esm/components/rating/rating.d.ts.map +1 -1
- package/lib/esm/components/rating/rating.js.map +1 -1
- package/lib/esm/components/select/combobox.d.ts.map +1 -1
- package/lib/esm/components/select/combobox.js +25 -15
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/config.d.ts +2 -2
- package/lib/esm/components/select/config.d.ts.map +1 -1
- package/lib/esm/components/select/config.js +10 -9
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/option.d.ts +2 -1
- package/lib/esm/components/select/option.d.ts.map +1 -1
- package/lib/esm/components/select/option.js +9 -3
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/remote.d.ts +1 -0
- package/lib/esm/components/select/remote.d.ts.map +1 -1
- package/lib/esm/components/select/remote.js +21 -14
- package/lib/esm/components/select/remote.js.map +1 -1
- package/lib/esm/components/select/search.d.ts +1 -1
- package/lib/esm/components/select/search.d.ts.map +1 -1
- package/lib/esm/components/select/search.js +34 -25
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.d.ts +5 -3
- package/lib/esm/components/select/select.d.ts.map +1 -1
- package/lib/esm/components/select/select.js +31 -31
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.d.ts.map +1 -1
- package/lib/esm/components/select/tags.js +22 -13
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.d.ts.map +1 -1
- package/lib/esm/components/select/templates.js +4 -4
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/types.d.ts +1 -1
- package/lib/esm/components/select/types.d.ts.map +1 -1
- package/lib/esm/components/select/utils.d.ts +4 -4
- package/lib/esm/components/select/utils.d.ts.map +1 -1
- package/lib/esm/components/select/utils.js +2 -3
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/components/sticky/sticky.d.ts +1 -1
- package/lib/esm/components/sticky/sticky.d.ts.map +1 -1
- package/lib/esm/components/sticky/sticky.js +13 -13
- package/lib/esm/components/sticky/sticky.js.map +1 -1
- package/lib/esm/components/theme-switch/theme-switch.d.ts +3 -0
- package/lib/esm/components/theme-switch/theme-switch.d.ts.map +1 -1
- package/lib/esm/components/theme-switch/theme-switch.js +17 -4
- package/lib/esm/components/theme-switch/theme-switch.js.map +1 -1
- package/lib/esm/components/toast/toast.d.ts.map +1 -1
- package/lib/esm/components/toast/toast.js +17 -9
- package/lib/esm/components/toast/toast.js.map +1 -1
- package/lib/esm/components/toast/types.d.ts +3 -0
- package/lib/esm/components/toast/types.d.ts.map +1 -1
- package/lib/esm/components/toggle/toggle.d.ts +2 -0
- package/lib/esm/components/toggle/toggle.d.ts.map +1 -1
- package/lib/esm/components/toggle/toggle.js +11 -2
- package/lib/esm/components/toggle/toggle.js.map +1 -1
- package/lib/esm/components/toggle-password/toggle-password.d.ts.map +1 -1
- package/lib/esm/components/toggle-password/toggle-password.js.map +1 -1
- package/lib/esm/helpers/dom.d.ts +4 -4
- package/lib/esm/helpers/dom.d.ts.map +1 -1
- package/lib/esm/helpers/dom.js +8 -10
- package/lib/esm/helpers/dom.js.map +1 -1
- package/lib/esm/helpers/event-handler.d.ts +1 -1
- package/lib/esm/helpers/event-handler.d.ts.map +1 -1
- package/lib/esm/helpers/event-handler.js +3 -1
- package/lib/esm/helpers/event-handler.js.map +1 -1
- package/lib/esm/helpers/utils.d.ts +1 -1
- package/lib/esm/helpers/utils.d.ts.map +1 -1
- package/lib/esm/helpers/utils.js +4 -1
- package/lib/esm/helpers/utils.js.map +1 -1
- package/lib/esm/index.d.ts +8 -0
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/index.js +6 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/types.d.ts +1 -1
- package/lib/esm/types.d.ts.map +1 -1
- package/package.json +5 -2
- package/src/components/carousel/__tests__/carousel.test.ts +326 -0
- package/src/components/carousel/carousel.css +42 -0
- package/src/components/carousel/carousel.ts +847 -0
- package/src/components/carousel/index.ts +11 -0
- package/src/components/carousel/types.ts +38 -0
- package/src/components/clipboard/__tests__/clipboard.test.ts +4 -4
- package/src/components/component.ts +15 -5
- package/src/components/datatable/__tests__/currency-sort.test.ts +4 -3
- package/src/components/datatable/__tests__/pagination-reset.test.ts +7 -4
- package/src/components/datatable/__tests__/setup.ts +1 -1
- package/src/components/datatable/datatable-checkbox.ts +6 -4
- package/src/components/datatable/datatable-sort.ts +27 -7
- package/src/components/datatable/datatable.ts +64 -37
- package/src/components/datatable/types.ts +3 -1
- package/src/components/drawer/drawer.ts +3 -18
- package/src/components/dropdown/dropdown.ts +2 -3
- package/src/components/modal/modal.ts +22 -14
- package/src/components/pin-input/__tests__/pin-input.test.ts +928 -0
- package/src/components/pin-input/index.ts +6 -0
- package/src/components/pin-input/pin-input.ts +499 -0
- package/src/components/pin-input/types.ts +45 -0
- package/src/components/rating/rating.ts +0 -1
- package/src/components/repeater/__tests__/repeater.test.ts +5 -5
- package/src/components/select/__tests__/ux-behaviors.test.ts +4 -3
- package/src/components/select/combobox.ts +23 -16
- package/src/components/select/config.ts +15 -14
- package/src/components/select/dropdown.ts +1 -1
- package/src/components/select/option.ts +14 -4
- package/src/components/select/remote.ts +68 -56
- package/src/components/select/search.ts +30 -27
- package/src/components/select/select.ts +41 -37
- package/src/components/select/tags.ts +14 -8
- package/src/components/select/templates.ts +11 -6
- package/src/components/select/types.ts +1 -1
- package/src/components/select/utils.ts +7 -9
- package/src/components/sticky/sticky.ts +2 -2
- package/src/components/theme-switch/theme-switch.ts +22 -4
- package/src/components/toast/toast.ts +34 -21
- package/src/components/toast/types.ts +5 -1
- package/src/components/toggle/toggle.ts +12 -2
- package/src/components/toggle-password/toggle-password.ts +0 -1
- package/src/helpers/dom.ts +14 -17
- package/src/helpers/event-handler.ts +5 -6
- package/src/helpers/utils.ts +5 -2
- package/src/index.ts +18 -0
- package/src/types.ts +1 -1
- package/styles.css +1 -0
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for KTPinInput
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import { KTPinInput } from '../pin-input';
|
|
7
|
+
|
|
8
|
+
function dispatchPaste(target: HTMLElement, text: string): boolean {
|
|
9
|
+
const ev = new Event('paste', { bubbles: true, cancelable: true });
|
|
10
|
+
Object.defineProperty(ev, 'clipboardData', {
|
|
11
|
+
value: {
|
|
12
|
+
getData: (type: string) =>
|
|
13
|
+
type === 'text' || type === 'text/plain' ? text : '',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
return target.dispatchEvent(ev);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createPinRoot(
|
|
20
|
+
opts: { count?: number; attrs?: Record<string, string> } = {},
|
|
21
|
+
): HTMLElement {
|
|
22
|
+
const { count = 4, attrs = {} } = opts;
|
|
23
|
+
const root = document.createElement('div');
|
|
24
|
+
root.setAttribute('data-kt-pin-input', 'true');
|
|
25
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
26
|
+
root.setAttribute(k, v);
|
|
27
|
+
}
|
|
28
|
+
for (let i = 0; i < count; i++) {
|
|
29
|
+
const input = document.createElement('input');
|
|
30
|
+
input.setAttribute('type', 'text');
|
|
31
|
+
input.setAttribute('data-kt-pin-input-item', 'true');
|
|
32
|
+
root.appendChild(input);
|
|
33
|
+
}
|
|
34
|
+
return root;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe('KTPinInput', () => {
|
|
38
|
+
let container: HTMLElement;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
document.body.innerHTML = '';
|
|
42
|
+
container = document.createElement('div');
|
|
43
|
+
document.body.appendChild(container);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
document.body.innerHTML = '';
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('initializes and stores instance on root', () => {
|
|
51
|
+
const root = createPinRoot();
|
|
52
|
+
container.appendChild(root);
|
|
53
|
+
const instance = new KTPinInput(root);
|
|
54
|
+
expect(instance.getElement()).toBe(root);
|
|
55
|
+
expect(KTPinInput.getInstance(root)).toBe(instance);
|
|
56
|
+
instance.dispose();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('returns null from getOrCreateInstance when no items', () => {
|
|
60
|
+
const root = document.createElement('div');
|
|
61
|
+
root.setAttribute('data-kt-pin-input', 'true');
|
|
62
|
+
container.appendChild(root);
|
|
63
|
+
expect(KTPinInput.getOrCreateInstance(root)).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('types digit and moves focus forward', () => {
|
|
67
|
+
const root = createPinRoot({ count: 3 });
|
|
68
|
+
container.appendChild(root);
|
|
69
|
+
const instance = new KTPinInput(root);
|
|
70
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
71
|
+
'[data-kt-pin-input-item]',
|
|
72
|
+
);
|
|
73
|
+
inputs[0].focus();
|
|
74
|
+
const ev = new KeyboardEvent('keydown', {
|
|
75
|
+
key: '5',
|
|
76
|
+
bubbles: true,
|
|
77
|
+
cancelable: true,
|
|
78
|
+
});
|
|
79
|
+
inputs[0].dispatchEvent(ev);
|
|
80
|
+
expect(inputs[0].value).toBe('5');
|
|
81
|
+
expect(document.activeElement).toBe(inputs[1]);
|
|
82
|
+
instance.dispose();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('routes a second digit to the next cell when the current cell is full', () => {
|
|
86
|
+
const root = createPinRoot({ count: 3 });
|
|
87
|
+
container.appendChild(root);
|
|
88
|
+
const instance = new KTPinInput(root);
|
|
89
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
90
|
+
'[data-kt-pin-input-item]',
|
|
91
|
+
);
|
|
92
|
+
inputs[0].value = '5';
|
|
93
|
+
inputs[0].focus();
|
|
94
|
+
inputs[0].setSelectionRange(1, 1);
|
|
95
|
+
inputs[0].dispatchEvent(
|
|
96
|
+
new KeyboardEvent('keydown', {
|
|
97
|
+
key: '6',
|
|
98
|
+
bubbles: true,
|
|
99
|
+
cancelable: true,
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
expect(inputs[0].value).toBe('5');
|
|
103
|
+
expect(inputs[1].value).toBe('6');
|
|
104
|
+
expect(document.activeElement).toBe(inputs[2]);
|
|
105
|
+
instance.dispose();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('sets maxLength 1 on each cell', () => {
|
|
109
|
+
const root = createPinRoot({ count: 2 });
|
|
110
|
+
container.appendChild(root);
|
|
111
|
+
const instance = new KTPinInput(root);
|
|
112
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
113
|
+
'[data-kt-pin-input-item]',
|
|
114
|
+
);
|
|
115
|
+
expect(inputs[0].maxLength).toBe(1);
|
|
116
|
+
expect(inputs[1].maxLength).toBe(1);
|
|
117
|
+
instance.dispose();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('backspace clears non-empty focused cell', () => {
|
|
121
|
+
const root = createPinRoot({ count: 2 });
|
|
122
|
+
container.appendChild(root);
|
|
123
|
+
const instance = new KTPinInput(root);
|
|
124
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
125
|
+
'[data-kt-pin-input-item]',
|
|
126
|
+
);
|
|
127
|
+
inputs[0].value = '4';
|
|
128
|
+
inputs[0].focus();
|
|
129
|
+
inputs[0].dispatchEvent(
|
|
130
|
+
new KeyboardEvent('keydown', {
|
|
131
|
+
key: 'Backspace',
|
|
132
|
+
bubbles: true,
|
|
133
|
+
cancelable: true,
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
expect(inputs[0].value).toBe('');
|
|
137
|
+
instance.dispose();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('backspace clears cell then moves to previous when empty', () => {
|
|
141
|
+
const root = createPinRoot({ count: 3 });
|
|
142
|
+
container.appendChild(root);
|
|
143
|
+
const instance = new KTPinInput(root);
|
|
144
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
145
|
+
'[data-kt-pin-input-item]',
|
|
146
|
+
);
|
|
147
|
+
inputs[0].value = '1';
|
|
148
|
+
inputs[1].focus();
|
|
149
|
+
const ev = new KeyboardEvent('keydown', {
|
|
150
|
+
key: 'Backspace',
|
|
151
|
+
bubbles: true,
|
|
152
|
+
cancelable: true,
|
|
153
|
+
});
|
|
154
|
+
inputs[1].dispatchEvent(ev);
|
|
155
|
+
expect(inputs[1].value).toBe('');
|
|
156
|
+
inputs[1].dispatchEvent(
|
|
157
|
+
new KeyboardEvent('keydown', {
|
|
158
|
+
key: 'Backspace',
|
|
159
|
+
bubbles: true,
|
|
160
|
+
cancelable: true,
|
|
161
|
+
}),
|
|
162
|
+
);
|
|
163
|
+
expect(document.activeElement).toBe(inputs[0]);
|
|
164
|
+
expect(inputs[0].value).toBe('1');
|
|
165
|
+
instance.dispose();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('arrow keys move focus', () => {
|
|
169
|
+
const root = createPinRoot({ count: 3 });
|
|
170
|
+
container.appendChild(root);
|
|
171
|
+
const instance = new KTPinInput(root);
|
|
172
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
173
|
+
'[data-kt-pin-input-item]',
|
|
174
|
+
);
|
|
175
|
+
inputs[1].focus();
|
|
176
|
+
inputs[1].dispatchEvent(
|
|
177
|
+
new KeyboardEvent('keydown', {
|
|
178
|
+
key: 'ArrowLeft',
|
|
179
|
+
bubbles: true,
|
|
180
|
+
cancelable: true,
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
expect(document.activeElement).toBe(inputs[0]);
|
|
184
|
+
inputs[0].dispatchEvent(
|
|
185
|
+
new KeyboardEvent('keydown', {
|
|
186
|
+
key: 'ArrowRight',
|
|
187
|
+
bubbles: true,
|
|
188
|
+
cancelable: true,
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
expect(document.activeElement).toBe(inputs[1]);
|
|
192
|
+
instance.dispose();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('distributes multi-character input (paste / autofill path)', () => {
|
|
196
|
+
const root = createPinRoot({ count: 4 });
|
|
197
|
+
container.appendChild(root);
|
|
198
|
+
const instance = new KTPinInput(root);
|
|
199
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
200
|
+
'[data-kt-pin-input-item]',
|
|
201
|
+
);
|
|
202
|
+
inputs[0].focus();
|
|
203
|
+
inputs[0].value = '12ab34';
|
|
204
|
+
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
205
|
+
expect(inputs[0].value).toBe('1');
|
|
206
|
+
expect(inputs[1].value).toBe('2');
|
|
207
|
+
expect(inputs[2].value).toBe('3');
|
|
208
|
+
expect(inputs[3].value).toBe('4');
|
|
209
|
+
instance.dispose();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('numeric pattern rejects letters', () => {
|
|
213
|
+
const root = createPinRoot();
|
|
214
|
+
container.appendChild(root);
|
|
215
|
+
const instance = new KTPinInput(root);
|
|
216
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
217
|
+
'[data-kt-pin-input-item]',
|
|
218
|
+
);
|
|
219
|
+
inputs[0].focus();
|
|
220
|
+
const ev = new KeyboardEvent('keydown', {
|
|
221
|
+
key: 'a',
|
|
222
|
+
bubbles: true,
|
|
223
|
+
cancelable: true,
|
|
224
|
+
});
|
|
225
|
+
inputs[0].dispatchEvent(ev);
|
|
226
|
+
expect(inputs[0].value).toBe('');
|
|
227
|
+
instance.dispose();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('custom availableChars allows hex', () => {
|
|
231
|
+
const root = createPinRoot({
|
|
232
|
+
attrs: { 'data-kt-pin-input-available-chars': '[0-9a-fA-F]' },
|
|
233
|
+
});
|
|
234
|
+
container.appendChild(root);
|
|
235
|
+
const instance = new KTPinInput(root);
|
|
236
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
237
|
+
'[data-kt-pin-input-item]',
|
|
238
|
+
);
|
|
239
|
+
inputs[0].focus();
|
|
240
|
+
inputs[0].dispatchEvent(
|
|
241
|
+
new KeyboardEvent('keydown', {
|
|
242
|
+
key: 'a',
|
|
243
|
+
bubbles: true,
|
|
244
|
+
cancelable: true,
|
|
245
|
+
}),
|
|
246
|
+
);
|
|
247
|
+
expect(inputs[0].value).toBe('a');
|
|
248
|
+
instance.dispose();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('fires complete when all cells filled', () => {
|
|
252
|
+
const root = createPinRoot({ count: 2 });
|
|
253
|
+
container.appendChild(root);
|
|
254
|
+
const instance = new KTPinInput(root);
|
|
255
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
256
|
+
'[data-kt-pin-input-item]',
|
|
257
|
+
);
|
|
258
|
+
const completes: unknown[] = [];
|
|
259
|
+
root.addEventListener('kt.pin-input.complete', (e) => {
|
|
260
|
+
completes.push((e as CustomEvent).detail?.payload);
|
|
261
|
+
});
|
|
262
|
+
inputs[0].focus();
|
|
263
|
+
inputs[0].dispatchEvent(
|
|
264
|
+
new KeyboardEvent('keydown', {
|
|
265
|
+
key: '1',
|
|
266
|
+
bubbles: true,
|
|
267
|
+
cancelable: true,
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
expect(completes.length).toBe(0);
|
|
271
|
+
inputs[1].dispatchEvent(
|
|
272
|
+
new KeyboardEvent('keydown', {
|
|
273
|
+
key: '2',
|
|
274
|
+
bubbles: true,
|
|
275
|
+
cancelable: true,
|
|
276
|
+
}),
|
|
277
|
+
);
|
|
278
|
+
expect(completes.length).toBe(1);
|
|
279
|
+
expect((completes[0] as { value: string }).value).toBe('12');
|
|
280
|
+
expect((completes[0] as { complete: boolean }).complete).toBe(true);
|
|
281
|
+
instance.dispose();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('skips disabled cells in paste distribution', () => {
|
|
285
|
+
const root = createPinRoot({ count: 4 });
|
|
286
|
+
container.appendChild(root);
|
|
287
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
288
|
+
'[data-kt-pin-input-item]',
|
|
289
|
+
);
|
|
290
|
+
inputs[2].disabled = true;
|
|
291
|
+
const instance = new KTPinInput(root);
|
|
292
|
+
inputs[0].focus();
|
|
293
|
+
inputs[0].value = '123';
|
|
294
|
+
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
295
|
+
expect(inputs[0].value).toBe('1');
|
|
296
|
+
expect(inputs[1].value).toBe('2');
|
|
297
|
+
expect(inputs[2].value).toBe('');
|
|
298
|
+
expect(inputs[3].value).toBe('3');
|
|
299
|
+
instance.dispose();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('getValue and setValue', () => {
|
|
303
|
+
const root = createPinRoot({ count: 3 });
|
|
304
|
+
container.appendChild(root);
|
|
305
|
+
const instance = new KTPinInput(root);
|
|
306
|
+
instance.setValue('789');
|
|
307
|
+
expect(instance.getValue()).toBe('789');
|
|
308
|
+
instance.setValue('');
|
|
309
|
+
expect(instance.getValue()).toBe('');
|
|
310
|
+
instance.dispose();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('dispose removes instance and listeners', () => {
|
|
314
|
+
const root = createPinRoot();
|
|
315
|
+
container.appendChild(root);
|
|
316
|
+
const instance = new KTPinInput(root);
|
|
317
|
+
instance.dispose();
|
|
318
|
+
expect(KTPinInput.getInstance(root)).toBeNull();
|
|
319
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
320
|
+
'[data-kt-pin-input-item]',
|
|
321
|
+
);
|
|
322
|
+
inputs[0].focus();
|
|
323
|
+
inputs[0].dispatchEvent(
|
|
324
|
+
new KeyboardEvent('keydown', {
|
|
325
|
+
key: '1',
|
|
326
|
+
bubbles: true,
|
|
327
|
+
cancelable: true,
|
|
328
|
+
}),
|
|
329
|
+
);
|
|
330
|
+
expect(inputs[0].value).toBe('');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('syncs hidden input when name is set', () => {
|
|
334
|
+
const root = createPinRoot({
|
|
335
|
+
count: 2,
|
|
336
|
+
attrs: { 'data-kt-pin-input-name': 'otp' },
|
|
337
|
+
});
|
|
338
|
+
container.appendChild(root);
|
|
339
|
+
const instance = new KTPinInput(root);
|
|
340
|
+
const hidden = root.querySelector<HTMLInputElement>(
|
|
341
|
+
'input[type="hidden"][data-kt-pin-input-hidden]',
|
|
342
|
+
);
|
|
343
|
+
expect(hidden).toBeTruthy();
|
|
344
|
+
expect(hidden?.name).toBe('otp');
|
|
345
|
+
instance.setValue('42');
|
|
346
|
+
expect(hidden?.value).toBe('42');
|
|
347
|
+
instance.dispose();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('lazy roots are skipped by createInstances', () => {
|
|
351
|
+
const root = createPinRoot();
|
|
352
|
+
root.setAttribute('data-kt-pin-input-lazy', 'true');
|
|
353
|
+
container.appendChild(root);
|
|
354
|
+
KTPinInput.createInstances();
|
|
355
|
+
expect(KTPinInput.getInstance(root)).toBeNull();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('getInstance returns null for falsy element', () => {
|
|
359
|
+
expect(KTPinInput.getInstance(null as unknown as HTMLElement)).toBeNull();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('getOrCreateInstance returns existing instance', () => {
|
|
363
|
+
const root = createPinRoot({ count: 2 });
|
|
364
|
+
container.appendChild(root);
|
|
365
|
+
const a = KTPinInput.getOrCreateInstance(root);
|
|
366
|
+
const b = KTPinInput.getOrCreateInstance(root);
|
|
367
|
+
expect(a).toBe(b);
|
|
368
|
+
a?.dispose();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('init delegates to createInstances', () => {
|
|
372
|
+
const root = createPinRoot({ count: 1 });
|
|
373
|
+
document.body.appendChild(root);
|
|
374
|
+
KTPinInput.init();
|
|
375
|
+
expect(KTPinInput.getInstance(root)).toBeTruthy();
|
|
376
|
+
KTPinInput.getInstance(root)?.dispose();
|
|
377
|
+
root.remove();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('createInstances initializes non-lazy roots in document', () => {
|
|
381
|
+
const root = createPinRoot({ count: 2 });
|
|
382
|
+
document.body.appendChild(root);
|
|
383
|
+
KTPinInput.createInstances();
|
|
384
|
+
const inst = KTPinInput.getInstance(root);
|
|
385
|
+
expect(inst).toBeTruthy();
|
|
386
|
+
inst?.dispose();
|
|
387
|
+
root.remove();
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it('does not register instance when root has no items', () => {
|
|
391
|
+
const root = document.createElement('div');
|
|
392
|
+
root.setAttribute('data-kt-pin-input', 'true');
|
|
393
|
+
container.appendChild(root);
|
|
394
|
+
new KTPinInput(root);
|
|
395
|
+
expect(KTPinInput.getInstance(root)).toBeNull();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('skips second constructor when instance already on connected root', () => {
|
|
399
|
+
const root = createPinRoot({ count: 1 });
|
|
400
|
+
container.appendChild(root);
|
|
401
|
+
const first = new KTPinInput(root);
|
|
402
|
+
const second = new KTPinInput(root);
|
|
403
|
+
expect(KTPinInput.getInstance(root)).toBe(first);
|
|
404
|
+
expect(second).not.toBe(first);
|
|
405
|
+
first.dispose();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('Home and End move focus to first and last cell', () => {
|
|
409
|
+
const root = createPinRoot({ count: 3 });
|
|
410
|
+
container.appendChild(root);
|
|
411
|
+
const instance = new KTPinInput(root);
|
|
412
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
413
|
+
'[data-kt-pin-input-item]',
|
|
414
|
+
);
|
|
415
|
+
inputs[1].focus();
|
|
416
|
+
inputs[1].dispatchEvent(
|
|
417
|
+
new KeyboardEvent('keydown', {
|
|
418
|
+
key: 'Home',
|
|
419
|
+
bubbles: true,
|
|
420
|
+
cancelable: true,
|
|
421
|
+
}),
|
|
422
|
+
);
|
|
423
|
+
expect(document.activeElement).toBe(inputs[0]);
|
|
424
|
+
inputs[0].dispatchEvent(
|
|
425
|
+
new KeyboardEvent('keydown', {
|
|
426
|
+
key: 'End',
|
|
427
|
+
bubbles: true,
|
|
428
|
+
cancelable: true,
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
expect(document.activeElement).toBe(inputs[2]);
|
|
432
|
+
instance.dispose();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('ignores printable keys with ctrl modifier', () => {
|
|
436
|
+
const root = createPinRoot({ count: 1 });
|
|
437
|
+
container.appendChild(root);
|
|
438
|
+
const instance = new KTPinInput(root);
|
|
439
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
440
|
+
'[data-kt-pin-input-item]',
|
|
441
|
+
);
|
|
442
|
+
inputs[0].focus();
|
|
443
|
+
inputs[0].value = '';
|
|
444
|
+
inputs[0].dispatchEvent(
|
|
445
|
+
new KeyboardEvent('keydown', {
|
|
446
|
+
key: '1',
|
|
447
|
+
ctrlKey: true,
|
|
448
|
+
bubbles: true,
|
|
449
|
+
cancelable: true,
|
|
450
|
+
}),
|
|
451
|
+
);
|
|
452
|
+
expect(inputs[0].value).toBe('');
|
|
453
|
+
instance.dispose();
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('keydown ignores disabled pin item as target', () => {
|
|
457
|
+
const root = createPinRoot({ count: 2 });
|
|
458
|
+
container.appendChild(root);
|
|
459
|
+
const instance = new KTPinInput(root);
|
|
460
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
461
|
+
'[data-kt-pin-input-item]',
|
|
462
|
+
);
|
|
463
|
+
inputs[0].disabled = true;
|
|
464
|
+
inputs[0].dispatchEvent(
|
|
465
|
+
new KeyboardEvent('keydown', {
|
|
466
|
+
key: '1',
|
|
467
|
+
bubbles: true,
|
|
468
|
+
cancelable: true,
|
|
469
|
+
}),
|
|
470
|
+
);
|
|
471
|
+
expect(inputs[0].value).toBe('');
|
|
472
|
+
instance.dispose();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('keydown ignores events whose target is not a pin cell', () => {
|
|
476
|
+
const root = createPinRoot({ count: 1 });
|
|
477
|
+
container.appendChild(root);
|
|
478
|
+
const instance = new KTPinInput(root);
|
|
479
|
+
const ev = new KeyboardEvent('keydown', {
|
|
480
|
+
key: '1',
|
|
481
|
+
bubbles: true,
|
|
482
|
+
cancelable: true,
|
|
483
|
+
});
|
|
484
|
+
Object.defineProperty(ev, 'target', {
|
|
485
|
+
value: document.body,
|
|
486
|
+
enumerable: true,
|
|
487
|
+
});
|
|
488
|
+
root.dispatchEvent(ev);
|
|
489
|
+
instance.dispose();
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('reuses existing hidden field when present', () => {
|
|
493
|
+
const root = createPinRoot({
|
|
494
|
+
count: 1,
|
|
495
|
+
attrs: { 'data-kt-pin-input-name': 'code' },
|
|
496
|
+
});
|
|
497
|
+
const existing = document.createElement('input');
|
|
498
|
+
existing.type = 'hidden';
|
|
499
|
+
existing.name = 'code';
|
|
500
|
+
existing.setAttribute('data-kt-pin-input-hidden', 'true');
|
|
501
|
+
root.appendChild(existing);
|
|
502
|
+
container.appendChild(root);
|
|
503
|
+
const instance = new KTPinInput(root);
|
|
504
|
+
const hiddens = root.querySelectorAll(
|
|
505
|
+
'input[type="hidden"][data-kt-pin-input-hidden]',
|
|
506
|
+
);
|
|
507
|
+
expect(hiddens.length).toBe(1);
|
|
508
|
+
expect(hiddens[0]).toBe(existing);
|
|
509
|
+
instance.dispose();
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('falls back to digits when availableChars is invalid regex', () => {
|
|
513
|
+
const root = createPinRoot({
|
|
514
|
+
attrs: { 'data-kt-pin-input-available-chars': '(' },
|
|
515
|
+
});
|
|
516
|
+
container.appendChild(root);
|
|
517
|
+
const instance = new KTPinInput(root);
|
|
518
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
519
|
+
'[data-kt-pin-input-item]',
|
|
520
|
+
);
|
|
521
|
+
inputs[0].focus();
|
|
522
|
+
inputs[0].dispatchEvent(
|
|
523
|
+
new KeyboardEvent('keydown', {
|
|
524
|
+
key: '7',
|
|
525
|
+
bubbles: true,
|
|
526
|
+
cancelable: true,
|
|
527
|
+
}),
|
|
528
|
+
);
|
|
529
|
+
expect(inputs[0].value).toBe('7');
|
|
530
|
+
inputs[0].dispatchEvent(
|
|
531
|
+
new KeyboardEvent('keydown', {
|
|
532
|
+
key: 'a',
|
|
533
|
+
bubbles: true,
|
|
534
|
+
cancelable: true,
|
|
535
|
+
}),
|
|
536
|
+
);
|
|
537
|
+
expect(inputs[0].value).toBe('7');
|
|
538
|
+
instance.dispose();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it('paste distributes filtered digits', () => {
|
|
542
|
+
const root = createPinRoot({ count: 3 });
|
|
543
|
+
container.appendChild(root);
|
|
544
|
+
const instance = new KTPinInput(root);
|
|
545
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
546
|
+
'[data-kt-pin-input-item]',
|
|
547
|
+
);
|
|
548
|
+
inputs[0].focus();
|
|
549
|
+
dispatchPaste(inputs[0], '8x9');
|
|
550
|
+
expect(inputs[0].value).toBe('8');
|
|
551
|
+
expect(inputs[1].value).toBe('9');
|
|
552
|
+
expect(inputs[2].value).toBe('');
|
|
553
|
+
instance.dispose();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('paste with empty text is a no-op for values', () => {
|
|
557
|
+
const root = createPinRoot({ count: 2 });
|
|
558
|
+
container.appendChild(root);
|
|
559
|
+
const instance = new KTPinInput(root);
|
|
560
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
561
|
+
'[data-kt-pin-input-item]',
|
|
562
|
+
);
|
|
563
|
+
inputs[0].value = '1';
|
|
564
|
+
inputs[0].focus();
|
|
565
|
+
dispatchPaste(inputs[0], '');
|
|
566
|
+
expect(inputs[0].value).toBe('1');
|
|
567
|
+
instance.dispose();
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it('paste ignores events whose target is not a pin cell', () => {
|
|
571
|
+
const root = createPinRoot({ count: 1 });
|
|
572
|
+
container.appendChild(root);
|
|
573
|
+
const instance = new KTPinInput(root);
|
|
574
|
+
const ev = new Event('paste', { bubbles: true, cancelable: true });
|
|
575
|
+
Object.defineProperty(ev, 'clipboardData', {
|
|
576
|
+
value: { getData: () => '99' },
|
|
577
|
+
});
|
|
578
|
+
Object.defineProperty(ev, 'target', {
|
|
579
|
+
value: document.body,
|
|
580
|
+
enumerable: true,
|
|
581
|
+
});
|
|
582
|
+
root.dispatchEvent(ev);
|
|
583
|
+
instance.dispose();
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
it('beforeinput insertFromPaste is prevented (paste handler applies)', () => {
|
|
587
|
+
const root = createPinRoot({ count: 2 });
|
|
588
|
+
container.appendChild(root);
|
|
589
|
+
const instance = new KTPinInput(root);
|
|
590
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
591
|
+
'[data-kt-pin-input-item]',
|
|
592
|
+
);
|
|
593
|
+
inputs[0].focus();
|
|
594
|
+
const ev = new InputEvent('beforeinput', {
|
|
595
|
+
bubbles: true,
|
|
596
|
+
cancelable: true,
|
|
597
|
+
inputType: 'insertFromPaste',
|
|
598
|
+
});
|
|
599
|
+
const prevented = !inputs[0].dispatchEvent(ev);
|
|
600
|
+
expect(prevented).toBe(true);
|
|
601
|
+
instance.dispose();
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('beforeinput insertText multi-char distributes', () => {
|
|
605
|
+
const root = createPinRoot({ count: 3 });
|
|
606
|
+
container.appendChild(root);
|
|
607
|
+
const instance = new KTPinInput(root);
|
|
608
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
609
|
+
'[data-kt-pin-input-item]',
|
|
610
|
+
);
|
|
611
|
+
inputs[0].focus();
|
|
612
|
+
inputs[0].dispatchEvent(
|
|
613
|
+
new InputEvent('beforeinput', {
|
|
614
|
+
bubbles: true,
|
|
615
|
+
cancelable: true,
|
|
616
|
+
inputType: 'insertText',
|
|
617
|
+
data: '12',
|
|
618
|
+
}),
|
|
619
|
+
);
|
|
620
|
+
expect(inputs[0].value).toBe('1');
|
|
621
|
+
expect(inputs[1].value).toBe('2');
|
|
622
|
+
instance.dispose();
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('beforeinput multi-char with no valid chars does not fill cells', () => {
|
|
626
|
+
const root = createPinRoot({ count: 2 });
|
|
627
|
+
container.appendChild(root);
|
|
628
|
+
const instance = new KTPinInput(root);
|
|
629
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
630
|
+
'[data-kt-pin-input-item]',
|
|
631
|
+
);
|
|
632
|
+
inputs[0].focus();
|
|
633
|
+
inputs[0].dispatchEvent(
|
|
634
|
+
new InputEvent('beforeinput', {
|
|
635
|
+
bubbles: true,
|
|
636
|
+
cancelable: true,
|
|
637
|
+
inputType: 'insertText',
|
|
638
|
+
data: 'ab',
|
|
639
|
+
}),
|
|
640
|
+
);
|
|
641
|
+
expect(inputs[0].value).toBe('');
|
|
642
|
+
expect(inputs[1].value).toBe('');
|
|
643
|
+
instance.dispose();
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
it('beforeinput rejects invalid single character', () => {
|
|
647
|
+
const root = createPinRoot({ count: 1 });
|
|
648
|
+
container.appendChild(root);
|
|
649
|
+
const instance = new KTPinInput(root);
|
|
650
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
651
|
+
'[data-kt-pin-input-item]',
|
|
652
|
+
);
|
|
653
|
+
inputs[0].focus();
|
|
654
|
+
const ev = new InputEvent('beforeinput', {
|
|
655
|
+
bubbles: true,
|
|
656
|
+
cancelable: true,
|
|
657
|
+
inputType: 'insertText',
|
|
658
|
+
data: 'z',
|
|
659
|
+
});
|
|
660
|
+
expect(inputs[0].dispatchEvent(ev)).toBe(false);
|
|
661
|
+
instance.dispose();
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it('beforeinput routes overflow digit when cell is full', () => {
|
|
665
|
+
const root = createPinRoot({ count: 2 });
|
|
666
|
+
container.appendChild(root);
|
|
667
|
+
const instance = new KTPinInput(root);
|
|
668
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
669
|
+
'[data-kt-pin-input-item]',
|
|
670
|
+
);
|
|
671
|
+
inputs[0].value = '3';
|
|
672
|
+
inputs[0].focus();
|
|
673
|
+
inputs[0].setSelectionRange(1, 1);
|
|
674
|
+
inputs[0].dispatchEvent(
|
|
675
|
+
new InputEvent('beforeinput', {
|
|
676
|
+
bubbles: true,
|
|
677
|
+
cancelable: true,
|
|
678
|
+
inputType: 'insertText',
|
|
679
|
+
data: '4',
|
|
680
|
+
}),
|
|
681
|
+
);
|
|
682
|
+
expect(inputs[0].value).toBe('3');
|
|
683
|
+
expect(inputs[1].value).toBe('4');
|
|
684
|
+
instance.dispose();
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('beforeinput insertFromYank is prevented', () => {
|
|
688
|
+
const root = createPinRoot({ count: 1 });
|
|
689
|
+
container.appendChild(root);
|
|
690
|
+
const instance = new KTPinInput(root);
|
|
691
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
692
|
+
'[data-kt-pin-input-item]',
|
|
693
|
+
);
|
|
694
|
+
inputs[0].focus();
|
|
695
|
+
const ev = new InputEvent('beforeinput', {
|
|
696
|
+
bubbles: true,
|
|
697
|
+
cancelable: true,
|
|
698
|
+
inputType: 'insertFromYank',
|
|
699
|
+
});
|
|
700
|
+
expect(inputs[0].dispatchEvent(ev)).toBe(false);
|
|
701
|
+
instance.dispose();
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it('beforeinput ignores events whose target is not a pin cell', () => {
|
|
705
|
+
const root = createPinRoot({ count: 1 });
|
|
706
|
+
container.appendChild(root);
|
|
707
|
+
const instance = new KTPinInput(root);
|
|
708
|
+
const ev = new InputEvent('beforeinput', {
|
|
709
|
+
bubbles: true,
|
|
710
|
+
cancelable: true,
|
|
711
|
+
inputType: 'insertText',
|
|
712
|
+
data: '1',
|
|
713
|
+
});
|
|
714
|
+
Object.defineProperty(ev, 'target', {
|
|
715
|
+
value: document.body,
|
|
716
|
+
enumerable: true,
|
|
717
|
+
});
|
|
718
|
+
root.dispatchEvent(ev);
|
|
719
|
+
instance.dispose();
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
it('beforeinput without inputType is ignored', () => {
|
|
723
|
+
const root = createPinRoot({ count: 1 });
|
|
724
|
+
container.appendChild(root);
|
|
725
|
+
const instance = new KTPinInput(root);
|
|
726
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
727
|
+
'[data-kt-pin-input-item]',
|
|
728
|
+
);
|
|
729
|
+
inputs[0].focus();
|
|
730
|
+
root.dispatchEvent(new Event('beforeinput', { bubbles: true }));
|
|
731
|
+
instance.dispose();
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
it('beforeinput non-insertText inputType returns early', () => {
|
|
735
|
+
const root = createPinRoot({ count: 1 });
|
|
736
|
+
container.appendChild(root);
|
|
737
|
+
const instance = new KTPinInput(root);
|
|
738
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
739
|
+
'[data-kt-pin-input-item]',
|
|
740
|
+
);
|
|
741
|
+
inputs[0].focus();
|
|
742
|
+
inputs[0].dispatchEvent(
|
|
743
|
+
new InputEvent('beforeinput', {
|
|
744
|
+
bubbles: true,
|
|
745
|
+
cancelable: true,
|
|
746
|
+
inputType: 'deleteContentBackward',
|
|
747
|
+
data: null,
|
|
748
|
+
}),
|
|
749
|
+
);
|
|
750
|
+
instance.dispose();
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it('beforeinput insertText with empty data returns early', () => {
|
|
754
|
+
const root = createPinRoot({ count: 1 });
|
|
755
|
+
container.appendChild(root);
|
|
756
|
+
const instance = new KTPinInput(root);
|
|
757
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
758
|
+
'[data-kt-pin-input-item]',
|
|
759
|
+
);
|
|
760
|
+
inputs[0].focus();
|
|
761
|
+
inputs[0].dispatchEvent(
|
|
762
|
+
new InputEvent('beforeinput', {
|
|
763
|
+
bubbles: true,
|
|
764
|
+
cancelable: true,
|
|
765
|
+
inputType: 'insertText',
|
|
766
|
+
data: '',
|
|
767
|
+
}),
|
|
768
|
+
);
|
|
769
|
+
instance.dispose();
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
it('beforeinput skips when isComposing', () => {
|
|
773
|
+
const root = createPinRoot({ count: 1 });
|
|
774
|
+
container.appendChild(root);
|
|
775
|
+
const instance = new KTPinInput(root);
|
|
776
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
777
|
+
'[data-kt-pin-input-item]',
|
|
778
|
+
);
|
|
779
|
+
inputs[0].focus();
|
|
780
|
+
const ev = new InputEvent('beforeinput', {
|
|
781
|
+
bubbles: true,
|
|
782
|
+
cancelable: true,
|
|
783
|
+
inputType: 'insertText',
|
|
784
|
+
data: '1',
|
|
785
|
+
});
|
|
786
|
+
Object.defineProperty(ev, 'isComposing', { value: true });
|
|
787
|
+
inputs[0].dispatchEvent(ev);
|
|
788
|
+
instance.dispose();
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
it('input event advances focus for single digit without keydown', () => {
|
|
792
|
+
const root = createPinRoot({ count: 2 });
|
|
793
|
+
container.appendChild(root);
|
|
794
|
+
const instance = new KTPinInput(root);
|
|
795
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
796
|
+
'[data-kt-pin-input-item]',
|
|
797
|
+
);
|
|
798
|
+
inputs[0].focus();
|
|
799
|
+
inputs[0].value = '5';
|
|
800
|
+
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
801
|
+
expect(document.activeElement).toBe(inputs[1]);
|
|
802
|
+
instance.dispose();
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it('input clears invalid single character', () => {
|
|
806
|
+
const root = createPinRoot({ count: 1 });
|
|
807
|
+
container.appendChild(root);
|
|
808
|
+
const instance = new KTPinInput(root);
|
|
809
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
810
|
+
'[data-kt-pin-input-item]',
|
|
811
|
+
);
|
|
812
|
+
inputs[0].focus();
|
|
813
|
+
inputs[0].value = 'x';
|
|
814
|
+
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
815
|
+
expect(inputs[0].value).toBe('');
|
|
816
|
+
instance.dispose();
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
it('input multi-character with all invalid clears and syncs', () => {
|
|
820
|
+
const root = createPinRoot({ count: 2 });
|
|
821
|
+
container.appendChild(root);
|
|
822
|
+
const instance = new KTPinInput(root);
|
|
823
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
824
|
+
'[data-kt-pin-input-item]',
|
|
825
|
+
);
|
|
826
|
+
inputs[0].focus();
|
|
827
|
+
inputs[0].value = 'xy';
|
|
828
|
+
inputs[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
829
|
+
expect(inputs[0].value).toBe('');
|
|
830
|
+
expect(inputs[1].value).toBe('');
|
|
831
|
+
instance.dispose();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
it('input ignores events from non-item targets', () => {
|
|
835
|
+
const root = createPinRoot({ count: 1 });
|
|
836
|
+
container.appendChild(root);
|
|
837
|
+
const instance = new KTPinInput(root);
|
|
838
|
+
const ev = new Event('input', { bubbles: true });
|
|
839
|
+
Object.defineProperty(ev, 'target', {
|
|
840
|
+
value: document.body,
|
|
841
|
+
enumerable: true,
|
|
842
|
+
});
|
|
843
|
+
root.dispatchEvent(ev);
|
|
844
|
+
instance.dispose();
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it('replace selection in cell types new digit in same cell', () => {
|
|
848
|
+
const root = createPinRoot({ count: 2 });
|
|
849
|
+
container.appendChild(root);
|
|
850
|
+
const instance = new KTPinInput(root);
|
|
851
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
852
|
+
'[data-kt-pin-input-item]',
|
|
853
|
+
);
|
|
854
|
+
inputs[0].value = '1';
|
|
855
|
+
inputs[0].focus();
|
|
856
|
+
inputs[0].setSelectionRange(0, 1);
|
|
857
|
+
inputs[0].dispatchEvent(
|
|
858
|
+
new KeyboardEvent('keydown', {
|
|
859
|
+
key: '9',
|
|
860
|
+
bubbles: true,
|
|
861
|
+
cancelable: true,
|
|
862
|
+
}),
|
|
863
|
+
);
|
|
864
|
+
expect(inputs[0].value).toBe('9');
|
|
865
|
+
expect(inputs[1].value).toBe('');
|
|
866
|
+
instance.dispose();
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
it('typing on last full cell does not change next (none)', () => {
|
|
870
|
+
const root = createPinRoot({ count: 2 });
|
|
871
|
+
container.appendChild(root);
|
|
872
|
+
const instance = new KTPinInput(root);
|
|
873
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
874
|
+
'[data-kt-pin-input-item]',
|
|
875
|
+
);
|
|
876
|
+
inputs[0].value = '1';
|
|
877
|
+
inputs[1].value = '2';
|
|
878
|
+
inputs[1].focus();
|
|
879
|
+
inputs[1].setSelectionRange(1, 1);
|
|
880
|
+
inputs[1].dispatchEvent(
|
|
881
|
+
new KeyboardEvent('keydown', {
|
|
882
|
+
key: '3',
|
|
883
|
+
bubbles: true,
|
|
884
|
+
cancelable: true,
|
|
885
|
+
}),
|
|
886
|
+
);
|
|
887
|
+
expect(inputs[0].value).toBe('1');
|
|
888
|
+
expect(inputs[1].value).toBe('2');
|
|
889
|
+
instance.dispose();
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it('setValue coerces non-string like empty', () => {
|
|
893
|
+
const root = createPinRoot({ count: 2 });
|
|
894
|
+
container.appendChild(root);
|
|
895
|
+
const instance = new KTPinInput(root);
|
|
896
|
+
instance.setValue(null as unknown as string);
|
|
897
|
+
expect(instance.getValue()).toBe('');
|
|
898
|
+
instance.dispose();
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
it('arrow past boundary does not throw', () => {
|
|
902
|
+
const root = createPinRoot({ count: 2 });
|
|
903
|
+
container.appendChild(root);
|
|
904
|
+
const instance = new KTPinInput(root);
|
|
905
|
+
const inputs = root.querySelectorAll<HTMLInputElement>(
|
|
906
|
+
'[data-kt-pin-input-item]',
|
|
907
|
+
);
|
|
908
|
+
inputs[0].focus();
|
|
909
|
+
inputs[0].dispatchEvent(
|
|
910
|
+
new KeyboardEvent('keydown', {
|
|
911
|
+
key: 'ArrowLeft',
|
|
912
|
+
bubbles: true,
|
|
913
|
+
cancelable: true,
|
|
914
|
+
}),
|
|
915
|
+
);
|
|
916
|
+
expect(document.activeElement).toBe(inputs[0]);
|
|
917
|
+
inputs[1].focus();
|
|
918
|
+
inputs[1].dispatchEvent(
|
|
919
|
+
new KeyboardEvent('keydown', {
|
|
920
|
+
key: 'ArrowRight',
|
|
921
|
+
bubbles: true,
|
|
922
|
+
cancelable: true,
|
|
923
|
+
}),
|
|
924
|
+
);
|
|
925
|
+
expect(document.activeElement).toBe(inputs[1]);
|
|
926
|
+
instance.dispose();
|
|
927
|
+
});
|
|
928
|
+
});
|