@keenthemes/ktui 1.2.0 → 1.2.1
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 +3349 -1550
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +1 -1
- package/lib/cjs/components/clipboard/clipboard.d.ts +37 -0
- package/lib/cjs/components/clipboard/clipboard.d.ts.map +1 -0
- package/lib/cjs/components/clipboard/clipboard.js +402 -0
- package/lib/cjs/components/clipboard/clipboard.js.map +1 -0
- package/lib/cjs/components/clipboard/index.d.ts +3 -0
- package/lib/cjs/components/clipboard/index.d.ts.map +1 -0
- package/lib/cjs/components/clipboard/index.js +6 -0
- package/lib/cjs/components/clipboard/index.js.map +1 -0
- package/lib/cjs/components/clipboard/types.d.ts +44 -0
- package/lib/cjs/components/clipboard/types.d.ts.map +1 -0
- package/lib/cjs/components/clipboard/types.js +7 -0
- package/lib/cjs/components/clipboard/types.js.map +1 -0
- package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/range-slider/index.d.ts +7 -0
- package/lib/cjs/components/range-slider/index.d.ts.map +1 -0
- package/lib/cjs/components/range-slider/index.js +10 -0
- package/lib/cjs/components/range-slider/index.js.map +1 -0
- package/lib/cjs/components/range-slider/range-slider.d.ts +42 -0
- package/lib/cjs/components/range-slider/range-slider.d.ts.map +1 -0
- package/lib/cjs/components/range-slider/range-slider.js +254 -0
- package/lib/cjs/components/range-slider/range-slider.js.map +1 -0
- package/lib/cjs/components/range-slider/types.d.ts +33 -0
- package/lib/cjs/components/range-slider/types.d.ts.map +1 -0
- package/lib/cjs/components/range-slider/types.js +7 -0
- package/lib/cjs/components/range-slider/types.js.map +1 -0
- package/lib/cjs/components/rating/rating.d.ts.map +1 -1
- package/lib/cjs/components/rating/rating.js +8 -3
- package/lib/cjs/components/rating/rating.js.map +1 -1
- package/lib/cjs/components/repeater/repeater.d.ts.map +1 -1
- package/lib/cjs/components/repeater/repeater.js +3 -2
- package/lib/cjs/components/repeater/repeater.js.map +1 -1
- package/lib/cjs/components/select/utils.d.ts.map +1 -1
- package/lib/cjs/components/select/utils.js +3 -1
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/components/sticky/sticky.d.ts.map +1 -1
- package/lib/cjs/components/sticky/sticky.js +3 -1
- package/lib/cjs/components/sticky/sticky.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/esm/components/clipboard/clipboard.d.ts +37 -0
- package/lib/esm/components/clipboard/clipboard.d.ts.map +1 -0
- package/lib/esm/components/clipboard/clipboard.js +399 -0
- package/lib/esm/components/clipboard/clipboard.js.map +1 -0
- package/lib/esm/components/clipboard/index.d.ts +3 -0
- package/lib/esm/components/clipboard/index.d.ts.map +1 -0
- package/lib/esm/components/clipboard/index.js +2 -0
- package/lib/esm/components/clipboard/index.js.map +1 -0
- package/lib/esm/components/clipboard/types.d.ts +44 -0
- package/lib/esm/components/clipboard/types.d.ts.map +1 -0
- package/lib/esm/components/clipboard/types.js +6 -0
- package/lib/esm/components/clipboard/types.js.map +1 -0
- package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/range-slider/index.d.ts +7 -0
- package/lib/esm/components/range-slider/index.d.ts.map +1 -0
- package/lib/esm/components/range-slider/index.js +6 -0
- package/lib/esm/components/range-slider/index.js.map +1 -0
- package/lib/esm/components/range-slider/range-slider.d.ts +42 -0
- package/lib/esm/components/range-slider/range-slider.d.ts.map +1 -0
- package/lib/esm/components/range-slider/range-slider.js +251 -0
- package/lib/esm/components/range-slider/range-slider.js.map +1 -0
- package/lib/esm/components/range-slider/types.d.ts +33 -0
- package/lib/esm/components/range-slider/types.d.ts.map +1 -0
- package/lib/esm/components/range-slider/types.js +6 -0
- package/lib/esm/components/range-slider/types.js.map +1 -0
- package/lib/esm/components/rating/rating.d.ts.map +1 -1
- package/lib/esm/components/rating/rating.js +8 -3
- package/lib/esm/components/rating/rating.js.map +1 -1
- package/lib/esm/components/repeater/repeater.d.ts.map +1 -1
- package/lib/esm/components/repeater/repeater.js +3 -2
- package/lib/esm/components/repeater/repeater.js.map +1 -1
- package/lib/esm/components/select/utils.d.ts.map +1 -1
- package/lib/esm/components/select/utils.js +3 -1
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/components/sticky/sticky.d.ts.map +1 -1
- package/lib/esm/components/sticky/sticky.js +3 -1
- package/lib/esm/components/sticky/sticky.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/package.json +1 -2
- package/src/components/clipboard/__tests__/clipboard.test.ts +438 -0
- package/src/components/clipboard/clipboard.ts +416 -0
- package/src/components/clipboard/index.ts +2 -0
- package/src/components/clipboard/types.ts +51 -0
- package/src/components/datatable/__tests__/currency-sort.test.ts +2 -10
- package/src/components/datatable/__tests__/multi-row-headers.test.ts +2 -2
- package/src/components/datatable/__tests__/race-conditions.test.ts +11 -14
- package/src/components/datatable/datatable.ts +3 -5
- package/src/components/range-slider/__tests__/range-slider.test.ts +659 -0
- package/src/components/range-slider/index.ts +11 -0
- package/src/components/range-slider/range-slider.ts +276 -0
- package/src/components/range-slider/types.ts +36 -0
- package/src/components/rating/__tests__/rating.test.ts +11 -4
- package/src/components/rating/rating.ts +22 -11
- package/src/components/repeater/__tests__/repeater.test.ts +19 -6
- package/src/components/repeater/repeater.ts +5 -3
- package/src/components/select/__tests__/ux-behaviors.test.ts +21 -3
- package/src/components/select/utils.ts +5 -1
- package/src/components/sticky/__tests__/sticky.test.ts +10 -3
- package/src/components/sticky/sticky.ts +14 -24
- package/src/components/sticky/types.ts +3 -3
- package/src/index.ts +17 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for KTClipboard component
|
|
3
|
+
*/
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { KTClipboard } from '../clipboard';
|
|
6
|
+
|
|
7
|
+
function flushPromises() {
|
|
8
|
+
return new Promise<void>((resolve) => {
|
|
9
|
+
setTimeout(() => resolve(), 0);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function createFixture(options?: {
|
|
14
|
+
withPredefinedText?: boolean;
|
|
15
|
+
predefinedTextValue?: string;
|
|
16
|
+
predefinedTextAttributeEmpty?: boolean;
|
|
17
|
+
action?: 'copy' | 'cut';
|
|
18
|
+
withTarget?: boolean;
|
|
19
|
+
targetExists?: boolean;
|
|
20
|
+
targetType?: 'input' | 'textarea' | 'div';
|
|
21
|
+
targetValue?: string;
|
|
22
|
+
targetTextContent?: string;
|
|
23
|
+
}) {
|
|
24
|
+
document.body.innerHTML = '';
|
|
25
|
+
|
|
26
|
+
const targetType = options?.targetType ?? 'input';
|
|
27
|
+
const targetId = 'kt-clipboard-target';
|
|
28
|
+
const targetExists = options?.targetExists ?? true;
|
|
29
|
+
|
|
30
|
+
const container = document.createElement('div');
|
|
31
|
+
|
|
32
|
+
const trigger = document.createElement('button');
|
|
33
|
+
trigger.type = 'button';
|
|
34
|
+
trigger.setAttribute('data-kt-clipboard', 'true');
|
|
35
|
+
|
|
36
|
+
if (options?.action) {
|
|
37
|
+
trigger.setAttribute('data-kt-clipboard-action', options.action);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (options?.withTarget) {
|
|
41
|
+
trigger.setAttribute('data-kt-clipboard-target', `#${targetId}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (options?.withPredefinedText) {
|
|
45
|
+
if (options.predefinedTextAttributeEmpty) {
|
|
46
|
+
trigger.setAttribute('data-kt-clipboard-text', '');
|
|
47
|
+
} else {
|
|
48
|
+
trigger.setAttribute(
|
|
49
|
+
'data-kt-clipboard-text',
|
|
50
|
+
options.predefinedTextValue ?? '',
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
trigger.textContent = 'Copy';
|
|
56
|
+
container.appendChild(trigger);
|
|
57
|
+
|
|
58
|
+
if (targetExists && options?.withTarget) {
|
|
59
|
+
if (targetType === 'input') {
|
|
60
|
+
const input = document.createElement('input');
|
|
61
|
+
input.id = targetId;
|
|
62
|
+
input.value = options?.targetValue ?? 'input value';
|
|
63
|
+
container.appendChild(input);
|
|
64
|
+
} else if (targetType === 'textarea') {
|
|
65
|
+
const textarea = document.createElement('textarea');
|
|
66
|
+
textarea.id = targetId;
|
|
67
|
+
textarea.value = options?.targetValue ?? 'textarea value';
|
|
68
|
+
container.appendChild(textarea);
|
|
69
|
+
} else {
|
|
70
|
+
const div = document.createElement('div');
|
|
71
|
+
div.id = targetId;
|
|
72
|
+
div.textContent = options?.targetTextContent ?? 'div text';
|
|
73
|
+
container.appendChild(div);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
document.body.appendChild(container);
|
|
78
|
+
|
|
79
|
+
return { container, trigger };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe('KTClipboard', () => {
|
|
83
|
+
let originalExecCommand: any;
|
|
84
|
+
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
// Ensure a clean clipboard state between tests.
|
|
87
|
+
originalExecCommand = document.execCommand;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(() => {
|
|
91
|
+
document.body.innerHTML = '';
|
|
92
|
+
// Restore execCommand (if it was replaced).
|
|
93
|
+
document.execCommand = originalExecCommand as any;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('copies predefined text (text wins over target)', async () => {
|
|
97
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
98
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
99
|
+
value: { writeText: writeTextMock },
|
|
100
|
+
configurable: true,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const { trigger } = createFixture({
|
|
104
|
+
withPredefinedText: true,
|
|
105
|
+
predefinedTextValue: 'hello',
|
|
106
|
+
withTarget: true,
|
|
107
|
+
targetExists: false, // target selector is missing; text must still win
|
|
108
|
+
action: 'copy',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const successEvents: CustomEvent[] = [];
|
|
112
|
+
trigger.addEventListener('kt.clipboard.success', (e) =>
|
|
113
|
+
successEvents.push(e as CustomEvent),
|
|
114
|
+
);
|
|
115
|
+
const errorEvents: CustomEvent[] = [];
|
|
116
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
117
|
+
errorEvents.push(e as CustomEvent),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
new KTClipboard(trigger);
|
|
121
|
+
trigger.click();
|
|
122
|
+
|
|
123
|
+
await flushPromises();
|
|
124
|
+
|
|
125
|
+
expect(writeTextMock).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(writeTextMock).toHaveBeenCalledWith('hello');
|
|
127
|
+
expect(successEvents.length).toBe(1);
|
|
128
|
+
expect(errorEvents.length).toBe(0);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('falls back to execCommand when Clipboard API is unavailable', async () => {
|
|
132
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
133
|
+
value: undefined,
|
|
134
|
+
configurable: true,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const execCommandMock = vi.fn().mockReturnValue(true);
|
|
138
|
+
document.execCommand = execCommandMock as any;
|
|
139
|
+
|
|
140
|
+
const { trigger } = createFixture({
|
|
141
|
+
withPredefinedText: true,
|
|
142
|
+
predefinedTextValue: 'fallback text',
|
|
143
|
+
action: 'copy',
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const successEvents: CustomEvent[] = [];
|
|
147
|
+
trigger.addEventListener('kt.clipboard.success', (e) =>
|
|
148
|
+
successEvents.push(e as CustomEvent),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
new KTClipboard(trigger);
|
|
152
|
+
trigger.click();
|
|
153
|
+
await flushPromises();
|
|
154
|
+
|
|
155
|
+
expect(execCommandMock).toHaveBeenCalledWith('copy');
|
|
156
|
+
expect(successEvents.length).toBe(1);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('dispatches error if fallback execCommand fails', async () => {
|
|
160
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
161
|
+
value: undefined,
|
|
162
|
+
configurable: true,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const execCommandMock = vi.fn().mockReturnValue(false);
|
|
166
|
+
document.execCommand = execCommandMock as any;
|
|
167
|
+
|
|
168
|
+
const { trigger } = createFixture({
|
|
169
|
+
withPredefinedText: true,
|
|
170
|
+
predefinedTextValue: 'will fail',
|
|
171
|
+
action: 'copy',
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const errorEvents: CustomEvent[] = [];
|
|
175
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
176
|
+
errorEvents.push(e as CustomEvent),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
new KTClipboard(trigger);
|
|
180
|
+
trigger.click();
|
|
181
|
+
await flushPromises();
|
|
182
|
+
|
|
183
|
+
expect(execCommandMock).toHaveBeenCalledWith('copy');
|
|
184
|
+
expect(errorEvents.length).toBe(1);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('dispatches error when data-kt-clipboard-text attribute is present but empty (and ignores target)', async () => {
|
|
188
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
189
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
190
|
+
value: { writeText: writeTextMock },
|
|
191
|
+
configurable: true,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const { trigger } = createFixture({
|
|
195
|
+
withPredefinedText: true,
|
|
196
|
+
predefinedTextAttributeEmpty: true,
|
|
197
|
+
withTarget: true,
|
|
198
|
+
targetType: 'input',
|
|
199
|
+
targetValue: 'should not be used',
|
|
200
|
+
action: 'copy',
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const successEvents: CustomEvent[] = [];
|
|
204
|
+
trigger.addEventListener('kt.clipboard.success', (e) =>
|
|
205
|
+
successEvents.push(e as CustomEvent),
|
|
206
|
+
);
|
|
207
|
+
const errorEvents: CustomEvent[] = [];
|
|
208
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
209
|
+
errorEvents.push(e as CustomEvent),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
new KTClipboard(trigger);
|
|
213
|
+
trigger.click();
|
|
214
|
+
await flushPromises();
|
|
215
|
+
|
|
216
|
+
expect(writeTextMock).not.toHaveBeenCalled();
|
|
217
|
+
expect(successEvents.length).toBe(0);
|
|
218
|
+
expect(errorEvents.length).toBe(1);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('dispatches error when Clipboard API writeText rejects', async () => {
|
|
222
|
+
const writeTextMock = vi
|
|
223
|
+
.fn()
|
|
224
|
+
.mockRejectedValue(new Error('NotAllowedError: permission denied'));
|
|
225
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
226
|
+
value: { writeText: writeTextMock },
|
|
227
|
+
configurable: true,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const { trigger } = createFixture({
|
|
231
|
+
withPredefinedText: true,
|
|
232
|
+
predefinedTextValue: 'hello',
|
|
233
|
+
action: 'copy',
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const errorEvents: CustomEvent[] = [];
|
|
237
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
238
|
+
errorEvents.push(e as CustomEvent),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
new KTClipboard(trigger);
|
|
242
|
+
trigger.click();
|
|
243
|
+
await flushPromises();
|
|
244
|
+
|
|
245
|
+
expect(writeTextMock).toHaveBeenCalledTimes(1);
|
|
246
|
+
expect(errorEvents.length).toBe(1);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('dispatches error for cut with predefined text when target is missing', async () => {
|
|
250
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
251
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
252
|
+
value: { writeText: writeTextMock },
|
|
253
|
+
configurable: true,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const { trigger } = createFixture({
|
|
257
|
+
withPredefinedText: true,
|
|
258
|
+
predefinedTextValue: 'hello',
|
|
259
|
+
withTarget: false,
|
|
260
|
+
action: 'cut',
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const errorEvents: CustomEvent[] = [];
|
|
264
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
265
|
+
errorEvents.push(e as CustomEvent),
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
new KTClipboard(trigger);
|
|
269
|
+
trigger.click();
|
|
270
|
+
await flushPromises();
|
|
271
|
+
|
|
272
|
+
expect(writeTextMock).not.toHaveBeenCalled();
|
|
273
|
+
expect(errorEvents.length).toBe(1);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('copies from input target value', async () => {
|
|
277
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
278
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
279
|
+
value: { writeText: writeTextMock },
|
|
280
|
+
configurable: true,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const { trigger } = createFixture({
|
|
284
|
+
withPredefinedText: false,
|
|
285
|
+
withTarget: true,
|
|
286
|
+
targetType: 'input',
|
|
287
|
+
targetValue: 'input value',
|
|
288
|
+
action: 'copy',
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
new KTClipboard(trigger);
|
|
292
|
+
trigger.click();
|
|
293
|
+
await flushPromises();
|
|
294
|
+
|
|
295
|
+
expect(writeTextMock).toHaveBeenCalledTimes(1);
|
|
296
|
+
expect(writeTextMock).toHaveBeenCalledWith('input value');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('copies from non-input target textContent', async () => {
|
|
300
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
301
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
302
|
+
value: { writeText: writeTextMock },
|
|
303
|
+
configurable: true,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const { trigger } = createFixture({
|
|
307
|
+
withPredefinedText: false,
|
|
308
|
+
withTarget: true,
|
|
309
|
+
targetType: 'div',
|
|
310
|
+
targetTextContent: 'div text content',
|
|
311
|
+
action: 'copy',
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
new KTClipboard(trigger);
|
|
315
|
+
trigger.click();
|
|
316
|
+
await flushPromises();
|
|
317
|
+
|
|
318
|
+
expect(writeTextMock).toHaveBeenCalledTimes(1);
|
|
319
|
+
expect(writeTextMock).toHaveBeenCalledWith('div text content');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('dispatches error when selector misses and no predefined text exists', async () => {
|
|
323
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
324
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
325
|
+
value: { writeText: writeTextMock },
|
|
326
|
+
configurable: true,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const { trigger } = createFixture({
|
|
330
|
+
withPredefinedText: false,
|
|
331
|
+
withTarget: true,
|
|
332
|
+
targetExists: false,
|
|
333
|
+
action: 'copy',
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const errorEvents: CustomEvent[] = [];
|
|
337
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
338
|
+
errorEvents.push(e as CustomEvent),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
new KTClipboard(trigger);
|
|
342
|
+
trigger.click();
|
|
343
|
+
await flushPromises();
|
|
344
|
+
|
|
345
|
+
expect(writeTextMock).not.toHaveBeenCalled();
|
|
346
|
+
expect(errorEvents.length).toBe(1);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it('dispatches error for cut when target is not input/textarea', async () => {
|
|
350
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
351
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
352
|
+
value: { writeText: writeTextMock },
|
|
353
|
+
configurable: true,
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const { trigger } = createFixture({
|
|
357
|
+
withPredefinedText: false,
|
|
358
|
+
withTarget: true,
|
|
359
|
+
targetType: 'div',
|
|
360
|
+
targetTextContent: 'not cuttable',
|
|
361
|
+
action: 'cut',
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const errorEvents: CustomEvent[] = [];
|
|
365
|
+
trigger.addEventListener('kt.clipboard.error', (e) =>
|
|
366
|
+
errorEvents.push(e as CustomEvent),
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
new KTClipboard(trigger);
|
|
370
|
+
trigger.click();
|
|
371
|
+
await flushPromises();
|
|
372
|
+
|
|
373
|
+
expect(writeTextMock).not.toHaveBeenCalled();
|
|
374
|
+
expect(errorEvents.length).toBe(1);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('cuts from input target (clears value on success)', async () => {
|
|
378
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
379
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
380
|
+
value: { writeText: writeTextMock },
|
|
381
|
+
configurable: true,
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const { trigger } = createFixture({
|
|
385
|
+
withPredefinedText: false,
|
|
386
|
+
withTarget: true,
|
|
387
|
+
targetType: 'input',
|
|
388
|
+
targetValue: 'cut value',
|
|
389
|
+
action: 'cut',
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const input = document.getElementById(
|
|
393
|
+
'kt-clipboard-target',
|
|
394
|
+
) as HTMLInputElement;
|
|
395
|
+
expect(input.value).toBe('cut value');
|
|
396
|
+
|
|
397
|
+
new KTClipboard(trigger);
|
|
398
|
+
trigger.click();
|
|
399
|
+
await flushPromises();
|
|
400
|
+
|
|
401
|
+
expect(writeTextMock).toHaveBeenCalledWith('cut value');
|
|
402
|
+
expect(input.value).toBe('');
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('is idempotent: createInstances does not double bind', async () => {
|
|
406
|
+
const writeTextMock = vi.fn().mockResolvedValue(undefined);
|
|
407
|
+
Object.defineProperty(navigator, 'clipboard', {
|
|
408
|
+
value: { writeText: writeTextMock },
|
|
409
|
+
configurable: true,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const { trigger } = createFixture({
|
|
413
|
+
withPredefinedText: true,
|
|
414
|
+
predefinedTextValue: 'once',
|
|
415
|
+
action: 'copy',
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Explicit instance creation.
|
|
419
|
+
new KTClipboard(trigger);
|
|
420
|
+
|
|
421
|
+
// Should not create another handler on the same element.
|
|
422
|
+
KTClipboard.createInstances();
|
|
423
|
+
|
|
424
|
+
trigger.click();
|
|
425
|
+
await flushPromises();
|
|
426
|
+
|
|
427
|
+
expect(writeTextMock).toHaveBeenCalledTimes(1);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('returns null for getInstance on non-initialized trigger', () => {
|
|
431
|
+
document.body.innerHTML = '';
|
|
432
|
+
const trigger = document.createElement('button');
|
|
433
|
+
trigger.setAttribute('data-kt-clipboard', 'true');
|
|
434
|
+
document.body.appendChild(trigger);
|
|
435
|
+
|
|
436
|
+
expect(KTClipboard.getInstance(trigger)).toBeNull();
|
|
437
|
+
});
|
|
438
|
+
});
|