@keenthemes/ktui 1.0.19 → 1.0.21

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.
Files changed (111) hide show
  1. package/dist/ktui.js +690 -166
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +165 -31
  5. package/examples/image-input/file-upload-example.html +189 -0
  6. package/examples/select/remote-data_.html +5 -0
  7. package/examples/select/test-optimizations.html +227 -0
  8. package/examples/select/test-remote-search.html +151 -0
  9. package/examples/sticky/README.md +158 -0
  10. package/examples/sticky/debug-sticky.html +144 -0
  11. package/examples/sticky/test-runner.html +175 -0
  12. package/examples/sticky/test-sticky-logic.js +369 -0
  13. package/examples/sticky/test-sticky-positioning.html +386 -0
  14. package/examples/toast/example.html +52 -0
  15. package/lib/cjs/components/component.js +59 -5
  16. package/lib/cjs/components/component.js.map +1 -1
  17. package/lib/cjs/components/datatable/datatable-sort.js +4 -0
  18. package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
  19. package/lib/cjs/components/datatable/datatable.js +79 -12
  20. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  21. package/lib/cjs/components/image-input/image-input.js +10 -2
  22. package/lib/cjs/components/image-input/image-input.js.map +1 -1
  23. package/lib/cjs/components/select/combobox.js +50 -20
  24. package/lib/cjs/components/select/combobox.js.map +1 -1
  25. package/lib/cjs/components/select/config.js +1 -0
  26. package/lib/cjs/components/select/config.js.map +1 -1
  27. package/lib/cjs/components/select/dropdown.js +4 -2
  28. package/lib/cjs/components/select/dropdown.js.map +1 -1
  29. package/lib/cjs/components/select/index.js.map +1 -1
  30. package/lib/cjs/components/select/option.js +2 -1
  31. package/lib/cjs/components/select/option.js.map +1 -1
  32. package/lib/cjs/components/select/remote.js +50 -50
  33. package/lib/cjs/components/select/remote.js.map +1 -1
  34. package/lib/cjs/components/select/search.js +15 -5
  35. package/lib/cjs/components/select/search.js.map +1 -1
  36. package/lib/cjs/components/select/select.js +273 -32
  37. package/lib/cjs/components/select/select.js.map +1 -1
  38. package/lib/cjs/components/select/tags.js +3 -1
  39. package/lib/cjs/components/select/tags.js.map +1 -1
  40. package/lib/cjs/components/select/templates.js +6 -0
  41. package/lib/cjs/components/select/templates.js.map +1 -1
  42. package/lib/cjs/components/select/utils.js +23 -10
  43. package/lib/cjs/components/select/utils.js.map +1 -1
  44. package/lib/cjs/components/stepper/stepper.js +59 -12
  45. package/lib/cjs/components/stepper/stepper.js.map +1 -1
  46. package/lib/cjs/components/sticky/sticky.js +52 -14
  47. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  48. package/lib/esm/components/component.js +59 -5
  49. package/lib/esm/components/component.js.map +1 -1
  50. package/lib/esm/components/datatable/datatable-sort.js +4 -0
  51. package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
  52. package/lib/esm/components/datatable/datatable.js +78 -12
  53. package/lib/esm/components/datatable/datatable.js.map +1 -1
  54. package/lib/esm/components/image-input/image-input.js +10 -2
  55. package/lib/esm/components/image-input/image-input.js.map +1 -1
  56. package/lib/esm/components/select/combobox.js +50 -20
  57. package/lib/esm/components/select/combobox.js.map +1 -1
  58. package/lib/esm/components/select/config.js +1 -0
  59. package/lib/esm/components/select/config.js.map +1 -1
  60. package/lib/esm/components/select/dropdown.js +4 -2
  61. package/lib/esm/components/select/dropdown.js.map +1 -1
  62. package/lib/esm/components/select/index.js +1 -1
  63. package/lib/esm/components/select/index.js.map +1 -1
  64. package/lib/esm/components/select/option.js +2 -1
  65. package/lib/esm/components/select/option.js.map +1 -1
  66. package/lib/esm/components/select/remote.js +50 -50
  67. package/lib/esm/components/select/remote.js.map +1 -1
  68. package/lib/esm/components/select/search.js +16 -6
  69. package/lib/esm/components/select/search.js.map +1 -1
  70. package/lib/esm/components/select/select.js +273 -32
  71. package/lib/esm/components/select/select.js.map +1 -1
  72. package/lib/esm/components/select/tags.js +3 -1
  73. package/lib/esm/components/select/tags.js.map +1 -1
  74. package/lib/esm/components/select/templates.js +6 -0
  75. package/lib/esm/components/select/templates.js.map +1 -1
  76. package/lib/esm/components/select/utils.js +23 -10
  77. package/lib/esm/components/select/utils.js.map +1 -1
  78. package/lib/esm/components/stepper/stepper.js +59 -12
  79. package/lib/esm/components/stepper/stepper.js.map +1 -1
  80. package/lib/esm/components/sticky/sticky.js +52 -14
  81. package/lib/esm/components/sticky/sticky.js.map +1 -1
  82. package/package.json +2 -2
  83. package/src/components/component.ts +19 -4
  84. package/src/components/datatable/datatable-sort.ts +6 -0
  85. package/src/components/datatable/datatable.ts +98 -15
  86. package/src/components/datatable/types.ts +5 -1
  87. package/src/components/image-input/image-input.ts +11 -2
  88. package/src/components/image-input/types.ts +1 -0
  89. package/src/components/input/input-group.css +1 -1
  90. package/src/components/input/input.css +1 -1
  91. package/src/components/scrollable/scrollable.css +3 -3
  92. package/src/components/select/combobox.ts +84 -34
  93. package/src/components/select/config.ts +2 -0
  94. package/src/components/select/dropdown.ts +20 -11
  95. package/src/components/select/index.ts +6 -1
  96. package/src/components/select/option.ts +7 -6
  97. package/src/components/select/remote.ts +51 -52
  98. package/src/components/select/search.ts +59 -44
  99. package/src/components/select/select.css +26 -17
  100. package/src/components/select/select.ts +472 -101
  101. package/src/components/select/tags.ts +9 -3
  102. package/src/components/select/templates.ts +10 -0
  103. package/src/components/select/utils.ts +55 -20
  104. package/src/components/select/variants.css +0 -1
  105. package/src/components/stepper/stepper.ts +2 -2
  106. package/src/components/sticky/sticky.ts +47 -16
  107. package/src/components/sticky/types.ts +3 -0
  108. package/src/components/table/table.css +1 -1
  109. package/src/components/textarea/textarea.css +1 -1
  110. package/src/components/toast/toast.css +84 -47
  111. package/src/components/toast/types.ts +3 -0
@@ -0,0 +1,369 @@
1
+ /**
2
+ * KTUI Sticky Component - Logic Test
3
+ * Tests the positioning logic changes from PR #27
4
+ */
5
+
6
+ import { KTSticky } from '../../lib/esm/components/sticky/index.js';
7
+
8
+ class StickyTestSuite {
9
+ constructor() {
10
+ this.testResults = [];
11
+ this.testElement = null;
12
+ }
13
+
14
+ // Setup test environment
15
+ setup() {
16
+ // Create a test container
17
+ const container = document.createElement('div');
18
+ container.id = 'sticky-test-container';
19
+ container.style.cssText = `
20
+ position: relative;
21
+ width: 100%;
22
+ height: 200vh;
23
+ background: #f0f0f0;
24
+ padding: 20px;
25
+ `;
26
+ document.body.appendChild(container);
27
+
28
+ // Create test element
29
+ this.testElement = document.createElement('div');
30
+ this.testElement.id = 'sticky-test-element';
31
+ this.testElement.style.cssText = `
32
+ width: 200px;
33
+ height: 100px;
34
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
35
+ color: white;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ font-weight: bold;
40
+ border-radius: 8px;
41
+ `;
42
+ container.appendChild(this.testElement);
43
+
44
+ console.log('✅ Test environment setup complete');
45
+ }
46
+
47
+ // Cleanup test environment
48
+ cleanup() {
49
+ const container = document.getElementById('sticky-test-container');
50
+ if (container) {
51
+ container.remove();
52
+ }
53
+ this.testResults = [];
54
+ console.log('✅ Test environment cleaned up');
55
+ }
56
+
57
+ // Test helper: create sticky instance with config
58
+ createStickyInstance(config) {
59
+ // Remove existing instance
60
+ if (this.testElement.hasAttribute('data-kt-sticky-initialized')) {
61
+ const existingInstance = KTSticky.getInstance(this.testElement);
62
+ if (existingInstance) {
63
+ // Force cleanup
64
+ this.testElement.classList.remove('active');
65
+ this.testElement.style.position = '';
66
+ this.testElement.style.top = '';
67
+ this.testElement.style.bottom = '';
68
+ this.testElement.style.left = '';
69
+ this.testElement.style.right = '';
70
+ this.testElement.style.insetBlockStart = '';
71
+ this.testElement.style.insetInlineStart = '';
72
+ this.testElement.style.insetInlineEnd = '';
73
+ }
74
+ }
75
+
76
+ // Clear attributes
77
+ this.testElement.removeAttribute('data-kt-sticky');
78
+ this.testElement.removeAttribute('data-kt-sticky-top');
79
+ this.testElement.removeAttribute('data-kt-sticky-bottom');
80
+ this.testElement.removeAttribute('data-kt-sticky-start');
81
+ this.testElement.removeAttribute('data-kt-sticky-end');
82
+ this.testElement.removeAttribute('data-kt-sticky-middle');
83
+ this.testElement.removeAttribute('data-kt-sticky-center');
84
+ this.testElement.removeAttribute('data-kt-sticky-name');
85
+
86
+ // Set new attributes based on config
87
+ this.testElement.setAttribute('data-kt-sticky', 'true');
88
+ this.testElement.setAttribute('data-kt-sticky-name', 'test');
89
+
90
+ if (config.top !== undefined) this.testElement.setAttribute('data-kt-sticky-top', config.top);
91
+ if (config.bottom !== undefined) this.testElement.setAttribute('data-kt-sticky-bottom', config.bottom);
92
+ if (config.start !== undefined) this.testElement.setAttribute('data-kt-sticky-start', config.start);
93
+ if (config.end !== undefined) this.testElement.setAttribute('data-kt-sticky-end', config.end);
94
+ if (config.middle !== undefined) this.testElement.setAttribute('data-kt-sticky-middle', config.middle);
95
+ if (config.center !== undefined) this.testElement.setAttribute('data-kt-sticky-center', config.center);
96
+
97
+ // Create new instance
98
+ return new KTSticky(this.testElement);
99
+ }
100
+
101
+ // Test helper: get computed styles
102
+ getComputedStyles() {
103
+ const computed = window.getComputedStyle(this.testElement);
104
+ return {
105
+ position: computed.position,
106
+ top: computed.top,
107
+ bottom: computed.bottom,
108
+ left: computed.left,
109
+ right: computed.right,
110
+ insetBlockStart: computed.insetBlockStart,
111
+ insetBlockEnd: computed.insetBlockEnd,
112
+ insetInlineStart: computed.insetInlineStart,
113
+ insetInlineEnd: computed.insetInlineEnd,
114
+ transform: computed.transform
115
+ };
116
+ }
117
+
118
+ // Test helper: simulate scroll to trigger sticky
119
+ simulateScroll() {
120
+ // Simulate scroll by triggering the scroll event
121
+ window.dispatchEvent(new Event('scroll'));
122
+
123
+ // Force a small delay to allow processing
124
+ return new Promise(resolve => setTimeout(resolve, 100));
125
+ }
126
+
127
+ // Test 1: Middle positioning
128
+ async testMiddlePositioning() {
129
+ console.log('🧪 Testing Middle (Vertical Center) Positioning...');
130
+
131
+ const instance = this.createStickyInstance({ middle: true });
132
+ await this.simulateScroll();
133
+
134
+ const styles = this.getComputedStyles();
135
+ const isMiddle = styles.insetBlockStart === '50%';
136
+
137
+ this.testResults.push({
138
+ test: 'Middle Positioning',
139
+ passed: isMiddle,
140
+ expected: 'insetBlockStart: 50%',
141
+ actual: `insetBlockStart: ${styles.insetBlockStart}`,
142
+ styles
143
+ });
144
+
145
+ console.log(isMiddle ? '✅ Middle positioning works' : '❌ Middle positioning failed');
146
+ return isMiddle;
147
+ }
148
+
149
+ // Test 2: Center positioning
150
+ async testCenterPositioning() {
151
+ console.log('🧪 Testing Center (Horizontal Center) Positioning...');
152
+
153
+ const instance = this.createStickyInstance({ center: true });
154
+ await this.simulateScroll();
155
+
156
+ const styles = this.getComputedStyles();
157
+ const isCenter = styles.insetInlineStart === '50%';
158
+
159
+ this.testResults.push({
160
+ test: 'Center Positioning',
161
+ passed: isCenter,
162
+ expected: 'insetInlineStart: 50%',
163
+ actual: `insetInlineStart: ${styles.insetInlineStart}`,
164
+ styles
165
+ });
166
+
167
+ console.log(isCenter ? '✅ Center positioning works' : '❌ Center positioning failed');
168
+ return isCenter;
169
+ }
170
+
171
+ // Test 3: Middle + Center positioning
172
+ async testMiddleCenterPositioning() {
173
+ console.log('🧪 Testing Middle + Center (Fully Centered) Positioning...');
174
+
175
+ const instance = this.createStickyInstance({ middle: true, center: true });
176
+ await this.simulateScroll();
177
+
178
+ const styles = this.getComputedStyles();
179
+ const isMiddleCenter = styles.insetBlockStart === '50%' && styles.insetInlineStart === '50%';
180
+
181
+ this.testResults.push({
182
+ test: 'Middle + Center Positioning',
183
+ passed: isMiddleCenter,
184
+ expected: 'insetBlockStart: 50%, insetInlineStart: 50%',
185
+ actual: `insetBlockStart: ${styles.insetBlockStart}, insetInlineStart: ${styles.insetInlineStart}`,
186
+ styles
187
+ });
188
+
189
+ console.log(isMiddleCenter ? '✅ Middle + Center positioning works' : '❌ Middle + Center positioning failed');
190
+ return isMiddleCenter;
191
+ }
192
+
193
+ // Test 4: Bottom positioning
194
+ async testBottomPositioning() {
195
+ console.log('🧪 Testing Bottom Positioning...');
196
+
197
+ const instance = this.createStickyInstance({ bottom: '20' });
198
+ await this.simulateScroll();
199
+
200
+ const styles = this.getComputedStyles();
201
+ const isBottom = styles.insetBlockEnd === '20px';
202
+
203
+ this.testResults.push({
204
+ test: 'Bottom Positioning',
205
+ passed: isBottom,
206
+ expected: 'insetBlockEnd: 20px',
207
+ actual: `insetBlockEnd: ${styles.insetBlockEnd}`,
208
+ styles
209
+ });
210
+
211
+ console.log(isBottom ? '✅ Bottom positioning works' : '❌ Bottom positioning failed');
212
+ return isBottom;
213
+ }
214
+
215
+ // Test 5: Auto positioning with offset calculation
216
+ async testAutoPositioning() {
217
+ console.log('🧪 Testing Auto Positioning with Offset Calculation...');
218
+
219
+ const instance = this.createStickyInstance({ start: 'auto', top: '50' });
220
+ await this.simulateScroll();
221
+
222
+ const styles = this.getComputedStyles();
223
+ const hasAutoOffset = styles.insetInlineStart !== 'auto' && styles.insetInlineStart !== '';
224
+
225
+ this.testResults.push({
226
+ test: 'Auto Positioning with Offset',
227
+ passed: hasAutoOffset,
228
+ expected: 'insetInlineStart: calculated offset value',
229
+ actual: `insetInlineStart: ${styles.insetInlineStart}`,
230
+ styles
231
+ });
232
+
233
+ console.log(hasAutoOffset ? '✅ Auto positioning with offset works' : '❌ Auto positioning with offset failed');
234
+ return hasAutoOffset;
235
+ }
236
+
237
+ // Test 6: Exclusive positioning logic (top vs bottom)
238
+ async testExclusivePositioning() {
239
+ console.log('🧪 Testing Exclusive Positioning Logic (top vs bottom)...');
240
+
241
+ const instance = this.createStickyInstance({ top: '30', bottom: '30' });
242
+ await this.simulateScroll();
243
+
244
+ const styles = this.getComputedStyles();
245
+ const isExclusive = styles.insetBlockStart === '30px' && styles.insetBlockEnd === 'auto';
246
+
247
+ this.testResults.push({
248
+ test: 'Exclusive Positioning Logic',
249
+ passed: isExclusive,
250
+ expected: 'insetBlockStart: 30px, insetBlockEnd: auto (top takes precedence)',
251
+ actual: `insetBlockStart: ${styles.insetBlockStart}, insetBlockEnd: ${styles.insetBlockEnd}`,
252
+ styles
253
+ });
254
+
255
+ console.log(isExclusive ? '✅ Exclusive positioning logic works' : '❌ Exclusive positioning logic failed');
256
+ return isExclusive;
257
+ }
258
+
259
+ // Test 7: Logical properties for RTL support
260
+ async testLogicalProperties() {
261
+ console.log('🧪 Testing Logical Properties for RTL Support...');
262
+
263
+ const instance = this.createStickyInstance({ end: '20', top: '40' });
264
+ await this.simulateScroll();
265
+
266
+ const styles = this.getComputedStyles();
267
+ const usesLogicalProps = styles.insetInlineEnd === '20px' && styles.insetBlockStart === '40px';
268
+
269
+ this.testResults.push({
270
+ test: 'Logical Properties (RTL Support)',
271
+ passed: usesLogicalProps,
272
+ expected: 'insetInlineEnd: 20px, insetBlockStart: 40px',
273
+ actual: `insetInlineEnd: ${styles.insetInlineEnd}, insetBlockStart: ${styles.insetBlockStart}`,
274
+ styles
275
+ });
276
+
277
+ console.log(usesLogicalProps ? '✅ Logical properties work' : '❌ Logical properties failed');
278
+ return usesLogicalProps;
279
+ }
280
+
281
+ // Test 8: Auto fallback values
282
+ async testAutoFallbackValues() {
283
+ console.log('🧪 Testing Auto Fallback Values...');
284
+
285
+ const instance = this.createStickyInstance({ top: 'auto' });
286
+ await this.simulateScroll();
287
+
288
+ const styles = this.getComputedStyles();
289
+ const hasAutoFallback = styles.insetBlockStart === '0px';
290
+
291
+ this.testResults.push({
292
+ test: 'Auto Fallback Values',
293
+ passed: hasAutoFallback,
294
+ expected: 'insetBlockStart: 0px (auto defaults to 0px)',
295
+ actual: `insetBlockStart: ${styles.insetBlockStart}`,
296
+ styles
297
+ });
298
+
299
+ console.log(hasAutoFallback ? '✅ Auto fallback values work' : '❌ Auto fallback values failed');
300
+ return hasAutoFallback;
301
+ }
302
+
303
+ // Run all tests
304
+ async runAllTests() {
305
+ console.log('🚀 Starting KTUI Sticky Component Tests...');
306
+ console.log('Testing PR #27 changes: middle, center, bottom positioning with improved offset logic\n');
307
+
308
+ this.setup();
309
+
310
+ try {
311
+ await this.testMiddlePositioning();
312
+ await this.testCenterPositioning();
313
+ await this.testMiddleCenterPositioning();
314
+ await this.testBottomPositioning();
315
+ await this.testAutoPositioning();
316
+ await this.testExclusivePositioning();
317
+ await this.testLogicalProperties();
318
+ await this.testAutoFallbackValues();
319
+
320
+ this.printResults();
321
+ } catch (error) {
322
+ console.error('❌ Test suite failed:', error);
323
+ } finally {
324
+ this.cleanup();
325
+ }
326
+ }
327
+
328
+ // Print test results
329
+ printResults() {
330
+ console.log('\n📊 Test Results Summary:');
331
+ console.log('='.repeat(60));
332
+
333
+ const passed = this.testResults.filter(r => r.passed).length;
334
+ const total = this.testResults.length;
335
+
336
+ this.testResults.forEach((result, index) => {
337
+ const status = result.passed ? '✅ PASS' : '❌ FAIL';
338
+ console.log(`${index + 1}. ${status} - ${result.test}`);
339
+ if (!result.passed) {
340
+ console.log(` Expected: ${result.expected}`);
341
+ console.log(` Actual: ${result.actual}`);
342
+ }
343
+ });
344
+
345
+ console.log('='.repeat(60));
346
+ console.log(`Overall: ${passed}/${total} tests passed`);
347
+
348
+ if (passed === total) {
349
+ console.log('🎉 All tests passed! PR #27 changes are working correctly.');
350
+ } else {
351
+ console.log('⚠️ Some tests failed. Please review the implementation.');
352
+ }
353
+ }
354
+ }
355
+
356
+ // Export for use in browser
357
+ if (typeof window !== 'undefined') {
358
+ window.StickyTestSuite = StickyTestSuite;
359
+ }
360
+
361
+ // Auto-run tests if this file is loaded directly
362
+ if (typeof document !== 'undefined') {
363
+ document.addEventListener('DOMContentLoaded', () => {
364
+ const testSuite = new StickyTestSuite();
365
+ testSuite.runAllTests();
366
+ });
367
+ }
368
+
369
+ export default StickyTestSuite;