@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,158 @@
1
+ # KTUI Sticky Component - Testing Suite
2
+
3
+ This directory contains comprehensive tests for the KTUI Sticky component, specifically designed to verify the changes from [PR #27](https://github.com/keenthemes/ktui/pull/27).
4
+
5
+ ## 🎯 What We're Testing
6
+
7
+ The tests verify the following new features and improvements:
8
+
9
+ ### New Positioning Features
10
+ - ✅ **Middle positioning** - Vertical centering (`inset-block-start: 50%`)
11
+ - ✅ **Center positioning** - Horizontal centering (`inset-inline-start: 50%`)
12
+ - ✅ **Bottom positioning** - Sticky to bottom with offset
13
+ - ✅ **Combined positioning** - Middle + Center for full centering
14
+
15
+ ### Improved Logic
16
+ - ✅ **Exclusive positioning** - Only one of `top`/`bottom` and `start`/`end` applied
17
+ - ✅ **Auto handling** - Proper fallback values for `'auto'` inputs
18
+ - ✅ **Offset calculation** - Dynamic positioning using `KTDom.offset()`
19
+
20
+ ### Modern CSS Support
21
+ - ✅ **Logical properties** - `insetBlockStart`, `insetInlineStart`, `insetInlineEnd`
22
+ - ✅ **RTL/LTR compatibility** - Better support for right-to-left layouts
23
+
24
+ ## 📁 Test Files
25
+
26
+ ### 1. `test-sticky-positioning.html`
27
+ **Visual/Interactive Test**
28
+ - Comprehensive visual test with 8 different positioning scenarios
29
+ - Real-time position indicator showing computed styles
30
+ - RTL toggle functionality
31
+ - Scroll indicators and controls
32
+
33
+ **How to use:**
34
+ ```bash
35
+ # Open in browser
36
+ open examples/sticky/test-sticky-positioning.html
37
+ ```
38
+
39
+ ### 2. `test-sticky-logic.js`
40
+ **Programmatic Test Suite**
41
+ - Automated tests for all positioning logic
42
+ - Validates computed CSS properties
43
+ - Tests exclusive positioning rules
44
+ - Verifies auto fallback values
45
+
46
+ ### 3. `test-runner.html`
47
+ **Test Runner Interface**
48
+ - Clean UI for running automated tests
49
+ - Detailed test results with pass/fail status
50
+ - Console output capture
51
+ - Visual test summary
52
+
53
+ **How to use:**
54
+ ```bash
55
+ # Open in browser
56
+ open examples/sticky/test-runner.html
57
+ ```
58
+
59
+ ## 🧪 Running the Tests
60
+
61
+ ### Option 1: Visual Testing (Recommended)
62
+ 1. Open `test-sticky-positioning.html` in your browser
63
+ 2. Scroll through the page to see each sticky element in action
64
+ 3. Use the position indicator to verify computed styles
65
+ 4. Test RTL layout by clicking "Toggle RTL Layout"
66
+
67
+ ### Option 2: Automated Testing
68
+ 1. Open `test-runner.html` in your browser
69
+ 2. Click "Run All Tests" to execute the automated test suite
70
+ 3. Review the detailed results and console output
71
+
72
+ ### Option 3: Console Testing
73
+ 1. Open browser developer tools
74
+ 2. Import and run the test suite directly:
75
+ ```javascript
76
+ import StickyTestSuite from './examples/sticky/test-sticky-logic.js';
77
+ const testSuite = new StickyTestSuite();
78
+ await testSuite.runAllTests();
79
+ ```
80
+
81
+ ## 📋 Test Scenarios
82
+
83
+ ### 1. Basic Positioning
84
+ - **Top**: `data-kt-sticky-top="20"` → `inset-block-start: 20px`
85
+ - **Bottom**: `data-kt-sticky-bottom="20"` → `inset-block-end: 20px`
86
+
87
+ ### 2. Centering
88
+ - **Middle**: `data-kt-sticky-middle="true"` → `inset-block-start: 50%`
89
+ - **Center**: `data-kt-sticky-center="true"` → `inset-inline-start: 50%`
90
+ - **Both**: `data-kt-sticky-middle="true" data-kt-sticky-center="true"` → Fully centered
91
+
92
+ ### 3. Auto Positioning
93
+ - **Auto Top**: `data-kt-sticky-top="auto"` → `inset-block-start: 0px`
94
+ - **Auto Start**: `data-kt-sticky-start="auto"` → Calculated offset using `KTDom.offset()`
95
+
96
+ ### 4. Exclusive Logic
97
+ - **Top + Bottom**: Only top is applied (top takes precedence)
98
+ - **Start + End**: Only start is applied (start takes precedence)
99
+
100
+ ### 5. RTL Support
101
+ - **End positioning**: `data-kt-sticky-end="20"` → `inset-inline-end: 20px`
102
+ - **Logical properties**: Works correctly in both LTR and RTL layouts
103
+
104
+ ## 🔍 What to Look For
105
+
106
+ ### ✅ Success Indicators
107
+ - Elements stick to the correct positions when scrolling
108
+ - Computed styles match expected values
109
+ - RTL layout works correctly
110
+ - Auto positioning calculates proper offsets
111
+ - Exclusive positioning rules are followed
112
+
113
+ ### ❌ Failure Indicators
114
+ - Elements don't stick or stick to wrong positions
115
+ - Computed styles don't match expected values
116
+ - RTL layout breaks positioning
117
+ - Auto positioning doesn't calculate offsets
118
+ - Multiple positioning properties conflict
119
+
120
+ ## 🛠️ Troubleshooting
121
+
122
+ ### Common Issues
123
+
124
+ 1. **Tests not running**
125
+ - Ensure you're serving files from a web server (not file://)
126
+ - Check browser console for import errors
127
+ - Verify KTUI library is built and accessible
128
+
129
+ 2. **Positioning not working**
130
+ - Check if sticky element has proper dimensions
131
+ - Verify scroll container is correct
132
+ - Ensure CSS logical properties are supported
133
+
134
+ 3. **RTL not working**
135
+ - Check if `dir="rtl"` is set on `<html>` element
136
+ - Verify browser supports logical properties
137
+ - Test with different RTL content
138
+
139
+ ### Debug Mode
140
+ Enable debug logging by adding this to the console:
141
+ ```javascript
142
+ localStorage.setItem('ktui-debug', 'true');
143
+ ```
144
+
145
+ ## 📊 Expected Results
146
+
147
+ When all tests pass, you should see:
148
+ - ✅ 8/8 tests passed
149
+ - All positioning scenarios working correctly
150
+ - Logical properties being used
151
+ - RTL layout functioning properly
152
+ - Auto positioning calculating offsets
153
+
154
+ ## 🔗 Related Links
155
+
156
+ - [PR #27](https://github.com/keenthemes/ktui/pull/27) - Original pull request
157
+ - [Sticky Component Documentation](../src/components/sticky/) - Component source code
158
+ - [KTUI Main Documentation](../../README.md) - Main project documentation
@@ -0,0 +1,144 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Debug Sticky Component</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ .debug-sticky {
10
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11
+ color: white;
12
+ padding: 1rem;
13
+ border-radius: 8px;
14
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
15
+ font-weight: 600;
16
+ text-align: center;
17
+ width: 200px;
18
+ height: 80px;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ }
23
+
24
+ .debug-sticky.active {
25
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
26
+ }
27
+
28
+ .debug-info {
29
+ position: fixed;
30
+ top: 10px;
31
+ left: 10px;
32
+ background: rgba(0, 0, 0, 0.8);
33
+ color: white;
34
+ padding: 1rem;
35
+ border-radius: 4px;
36
+ font-family: monospace;
37
+ font-size: 12px;
38
+ max-width: 400px;
39
+ z-index: 9999;
40
+ }
41
+ </style>
42
+ </head>
43
+ <body class="bg-gray-50">
44
+ <div class="debug-info" id="debugInfo">
45
+ Loading...
46
+ </div>
47
+
48
+ <!-- Simple test section -->
49
+ <div style="height: 100vh; padding: 2rem;">
50
+ <h1>Debug Sticky Component</h1>
51
+ <p>Scroll down to test the sticky element</p>
52
+ </div>
53
+
54
+ <!-- Single sticky element for testing -->
55
+ <div class="debug-sticky"
56
+ data-kt-sticky="true"
57
+ data-kt-sticky-top="20"
58
+ data-kt-sticky-offset="100"
59
+ data-kt-sticky-zindex="1000"
60
+ data-kt-sticky-name="debug-test">
61
+ Debug Sticky
62
+ </div>
63
+
64
+ <!-- Content to scroll through -->
65
+ <div style="height: 200vh; padding: 2rem;">
66
+ <h2>Scroll Content</h2>
67
+ <p>This content is here to allow scrolling and test the sticky element.</p>
68
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
69
+ <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
70
+ <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
71
+ <p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
72
+ </div>
73
+
74
+ <!-- Load KTUI -->
75
+ <script src="../../dist/ktui.js"></script>
76
+ <script>
77
+ document.addEventListener('DOMContentLoaded', function() {
78
+ const debugInfo = document.getElementById('debugInfo');
79
+
80
+ function updateDebugInfo() {
81
+ const stickyElement = document.querySelector('[data-kt-sticky]');
82
+ const initializedElement = document.querySelector('[data-kt-sticky-initialized]');
83
+ const activeElement = document.querySelector('[data-kt-sticky-initialized].active');
84
+
85
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
86
+ const viewportHeight = window.innerHeight;
87
+
88
+ let info = `
89
+ <strong>Debug Info:</strong><br>
90
+ Scroll: ${scrollTop}px<br>
91
+ Viewport Height: ${viewportHeight}px<br>
92
+ KTSticky Available: ${!!window.KTSticky}<br>
93
+ Sticky Elements: ${document.querySelectorAll('[data-kt-sticky]').length}<br>
94
+ Initialized Elements: ${document.querySelectorAll('[data-kt-sticky-initialized]').length}<br>
95
+ Active Elements: ${document.querySelectorAll('[data-kt-sticky-initialized].active').length}<br>
96
+ `;
97
+
98
+ if (stickyElement) {
99
+ const computedStyle = window.getComputedStyle(stickyElement);
100
+ const height = stickyElement.offsetHeight;
101
+ const top = stickyElement.getAttribute('data-kt-sticky-top') || '0';
102
+ const offset = stickyElement.getAttribute('data-kt-sticky-offset') || '0';
103
+
104
+ info += `
105
+ <br><strong>Sticky Element:</strong><br>
106
+ Height: ${height}px<br>
107
+ Top: ${top}px<br>
108
+ Offset: ${offset}px<br>
109
+ Height + Top: ${height + parseInt(top)}px<br>
110
+ Position: ${computedStyle.position}<br>
111
+ Z-Index: ${computedStyle.zIndex}<br>
112
+ InsetBlockStart: ${computedStyle.insetBlockStart}<br>
113
+ `;
114
+ }
115
+
116
+ if (initializedElement) {
117
+ info += `<br><strong>Initialized Element:</strong><br>`;
118
+ info += `Classes: ${initializedElement.className}<br>`;
119
+ info += `Data Attributes: ${Array.from(initializedElement.attributes).filter(attr => attr.name.startsWith('data-kt-sticky')).map(attr => `${attr.name}="${attr.value}"`).join(', ')}<br>`;
120
+ }
121
+
122
+ debugInfo.innerHTML = info;
123
+ }
124
+
125
+ // Initialize KTUI
126
+ if (window.KTSticky) {
127
+ console.log('Initializing KTSticky...');
128
+ window.KTSticky.init();
129
+ console.log('KTSticky initialized');
130
+ } else {
131
+ console.error('KTSticky not found!');
132
+ }
133
+
134
+ // Update debug info initially and on scroll
135
+ updateDebugInfo();
136
+ window.addEventListener('scroll', updateDebugInfo);
137
+ window.addEventListener('resize', updateDebugInfo);
138
+
139
+ // Update every second to catch any changes
140
+ setInterval(updateDebugInfo, 1000);
141
+ });
142
+ </script>
143
+ </body>
144
+ </html>
@@ -0,0 +1,175 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>KTUI Sticky Component - Test Runner</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ .test-result {
10
+ padding: 1rem;
11
+ margin: 0.5rem 0;
12
+ border-radius: 8px;
13
+ border-left: 4px solid;
14
+ }
15
+
16
+ .test-result.pass {
17
+ background: #f0fdf4;
18
+ border-left-color: #22c55e;
19
+ }
20
+
21
+ .test-result.fail {
22
+ background: #fef2f2;
23
+ border-left-color: #ef4444;
24
+ }
25
+
26
+ .test-details {
27
+ font-family: monospace;
28
+ font-size: 0.875rem;
29
+ background: #f8fafc;
30
+ padding: 0.5rem;
31
+ border-radius: 4px;
32
+ margin-top: 0.5rem;
33
+ }
34
+ </style>
35
+ </head>
36
+ <body class="bg-gray-50 p-8">
37
+ <div class="max-w-4xl mx-auto">
38
+ <h1 class="text-3xl font-bold mb-8">KTUI Sticky Component - Test Runner</h1>
39
+ <p class="text-gray-600 mb-8">Testing PR #27 changes: middle, center, bottom positioning with improved offset logic</p>
40
+
41
+ <div class="bg-white rounded-lg shadow-md p-6 mb-8">
42
+ <h2 class="text-xl font-semibold mb-4">Test Controls</h2>
43
+ <div class="space-x-4">
44
+ <button id="runTests" class="bg-blue-500 text-white px-6 py-2 rounded hover:bg-blue-600">
45
+ Run All Tests
46
+ </button>
47
+ <button id="clearResults" class="bg-gray-500 text-white px-6 py-2 rounded hover:bg-gray-600">
48
+ Clear Results
49
+ </button>
50
+ </div>
51
+ </div>
52
+
53
+ <div id="testResults" class="space-y-4">
54
+ <div class="text-center text-gray-500 py-8">
55
+ Click "Run All Tests" to start testing the sticky component
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <script type="module">
61
+ import StickyTestSuite from './test-sticky-logic.js';
62
+
63
+ const runTestsBtn = document.getElementById('runTests');
64
+ const clearResultsBtn = document.getElementById('clearResults');
65
+ const testResultsDiv = document.getElementById('testResults');
66
+
67
+ let testSuite = null;
68
+
69
+ runTestsBtn.addEventListener('click', async () => {
70
+ // Disable button during testing
71
+ runTestsBtn.disabled = true;
72
+ runTestsBtn.textContent = 'Running Tests...';
73
+
74
+ // Clear previous results
75
+ testResultsDiv.innerHTML = '<div class="text-center text-gray-500 py-8">Running tests...</div>';
76
+
77
+ try {
78
+ // Create and run test suite
79
+ testSuite = new StickyTestSuite();
80
+
81
+ // Override console.log to capture test output
82
+ const originalLog = console.log;
83
+ const testOutput = [];
84
+
85
+ console.log = (...args) => {
86
+ originalLog.apply(console, args);
87
+ testOutput.push(args.join(' '));
88
+ };
89
+
90
+ // Run tests
91
+ await testSuite.runAllTests();
92
+
93
+ // Restore console.log
94
+ console.log = originalLog;
95
+
96
+ // Display results
97
+ displayResults(testSuite.testResults, testOutput);
98
+
99
+ } catch (error) {
100
+ console.error('Test execution failed:', error);
101
+ testResultsDiv.innerHTML = `
102
+ <div class="test-result fail">
103
+ <h3 class="font-semibold">Test Execution Failed</h3>
104
+ <p class="text-red-600">${error.message}</p>
105
+ </div>
106
+ `;
107
+ } finally {
108
+ // Re-enable button
109
+ runTestsBtn.disabled = false;
110
+ runTestsBtn.textContent = 'Run All Tests';
111
+ }
112
+ });
113
+
114
+ clearResultsBtn.addEventListener('click', () => {
115
+ testResultsDiv.innerHTML = '<div class="text-center text-gray-500 py-8">Click "Run All Tests" to start testing the sticky component</div>';
116
+ });
117
+
118
+ function displayResults(results, output) {
119
+ const passed = results.filter(r => r.passed).length;
120
+ const total = results.length;
121
+
122
+ let html = `
123
+ <div class="bg-white rounded-lg shadow-md p-6 mb-6">
124
+ <h2 class="text-xl font-semibold mb-4">Test Summary</h2>
125
+ <div class="flex items-center space-x-4">
126
+ <div class="text-2xl font-bold ${passed === total ? 'text-green-600' : 'text-red-600'}">
127
+ ${passed}/${total}
128
+ </div>
129
+ <div class="text-gray-600">
130
+ tests passed
131
+ </div>
132
+ <div class="text-sm text-gray-500">
133
+ ${((passed / total) * 100).toFixed(1)}% success rate
134
+ </div>
135
+ </div>
136
+ </div>
137
+ `;
138
+
139
+ results.forEach((result, index) => {
140
+ const resultClass = result.passed ? 'pass' : 'fail';
141
+ const statusIcon = result.passed ? '✅' : '❌';
142
+
143
+ html += `
144
+ <div class="test-result ${resultClass}">
145
+ <h3 class="font-semibold">${statusIcon} ${result.test}</h3>
146
+ <p class="text-sm text-gray-600 mt-1">${result.expected}</p>
147
+ <div class="test-details">
148
+ <div><strong>Actual:</strong> ${result.actual}</div>
149
+ <div><strong>Position:</strong> ${result.styles.position}</div>
150
+ <div><strong>InsetBlockStart:</strong> ${result.styles.insetBlockStart}</div>
151
+ <div><strong>InsetBlockEnd:</strong> ${result.styles.insetBlockEnd}</div>
152
+ <div><strong>InsetInlineStart:</strong> ${result.styles.insetInlineStart}</div>
153
+ <div><strong>InsetInlineEnd:</strong> ${result.styles.insetInlineEnd}</div>
154
+ </div>
155
+ </div>
156
+ `;
157
+ });
158
+
159
+ // Add console output
160
+ if (output.length > 0) {
161
+ html += `
162
+ <div class="bg-white rounded-lg shadow-md p-6">
163
+ <h2 class="text-xl font-semibold mb-4">Console Output</h2>
164
+ <div class="bg-gray-900 text-green-400 p-4 rounded font-mono text-sm overflow-auto max-h-96">
165
+ ${output.map(line => `<div>${line}</div>`).join('')}
166
+ </div>
167
+ </div>
168
+ `;
169
+ }
170
+
171
+ testResultsDiv.innerHTML = html;
172
+ }
173
+ </script>
174
+ </body>
175
+ </html>