@keenthemes/ktui 1.2.3 → 1.2.5

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 (213) hide show
  1. package/dist/ktui.js +2244 -1061
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +185 -40
  5. package/lib/cjs/components/context-menu/context-menu.d.ts +66 -0
  6. package/lib/cjs/components/context-menu/context-menu.d.ts.map +1 -0
  7. package/lib/cjs/components/context-menu/context-menu.js +423 -0
  8. package/lib/cjs/components/context-menu/context-menu.js.map +1 -0
  9. package/lib/cjs/components/context-menu/index.d.ts +7 -0
  10. package/lib/cjs/components/context-menu/index.d.ts.map +1 -0
  11. package/lib/cjs/components/context-menu/index.js +10 -0
  12. package/lib/cjs/components/context-menu/index.js.map +1 -0
  13. package/lib/cjs/components/context-menu/types.d.ts +30 -0
  14. package/lib/cjs/components/context-menu/types.d.ts.map +1 -0
  15. package/lib/cjs/components/context-menu/types.js +7 -0
  16. package/lib/cjs/components/context-menu/types.js.map +1 -0
  17. package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
  18. package/lib/cjs/components/datatable/datatable-checkbox.js +34 -15
  19. package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
  20. package/lib/cjs/components/datatable/datatable-contracts.d.ts +66 -0
  21. package/lib/cjs/components/datatable/datatable-contracts.d.ts.map +1 -0
  22. package/lib/cjs/components/datatable/datatable-contracts.js +7 -0
  23. package/lib/cjs/components/datatable/datatable-contracts.js.map +1 -0
  24. package/lib/cjs/components/datatable/datatable-event-adapter.d.ts +7 -0
  25. package/lib/cjs/components/datatable/datatable-event-adapter.d.ts.map +1 -0
  26. package/lib/cjs/components/datatable/datatable-event-adapter.js +16 -0
  27. package/lib/cjs/components/datatable/datatable-event-adapter.js.map +1 -0
  28. package/lib/cjs/components/datatable/datatable-local-provider.d.ts +25 -0
  29. package/lib/cjs/components/datatable/datatable-local-provider.d.ts.map +1 -0
  30. package/lib/cjs/components/datatable/datatable-local-provider.js +190 -0
  31. package/lib/cjs/components/datatable/datatable-local-provider.js.map +1 -0
  32. package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts +15 -0
  33. package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts.map +1 -0
  34. package/lib/cjs/components/datatable/datatable-pagination-renderer.js +144 -0
  35. package/lib/cjs/components/datatable/datatable-pagination-renderer.js.map +1 -0
  36. package/lib/cjs/components/datatable/datatable-remote-provider.d.ts +25 -0
  37. package/lib/cjs/components/datatable/datatable-remote-provider.d.ts.map +1 -0
  38. package/lib/cjs/components/datatable/datatable-remote-provider.js +191 -0
  39. package/lib/cjs/components/datatable/datatable-remote-provider.js.map +1 -0
  40. package/lib/cjs/components/datatable/datatable-state-store.d.ts +21 -0
  41. package/lib/cjs/components/datatable/datatable-state-store.d.ts.map +1 -0
  42. package/lib/cjs/components/datatable/datatable-state-store.js +81 -0
  43. package/lib/cjs/components/datatable/datatable-state-store.js.map +1 -0
  44. package/lib/cjs/components/datatable/datatable-table-renderer.d.ts +16 -0
  45. package/lib/cjs/components/datatable/datatable-table-renderer.d.ts.map +1 -0
  46. package/lib/cjs/components/datatable/datatable-table-renderer.js +141 -0
  47. package/lib/cjs/components/datatable/datatable-table-renderer.js.map +1 -0
  48. package/lib/cjs/components/datatable/datatable.d.ts +9 -87
  49. package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
  50. package/lib/cjs/components/datatable/datatable.js +234 -740
  51. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  52. package/lib/cjs/components/dropdown/dropdown.d.ts +2 -2
  53. package/lib/cjs/components/dropdown/dropdown.d.ts.map +1 -1
  54. package/lib/cjs/components/dropdown/dropdown.js +68 -31
  55. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  56. package/lib/cjs/components/input-number/index.d.ts +7 -0
  57. package/lib/cjs/components/input-number/index.d.ts.map +1 -0
  58. package/lib/cjs/components/input-number/index.js +10 -0
  59. package/lib/cjs/components/input-number/index.js.map +1 -0
  60. package/lib/cjs/components/input-number/input-number.d.ts +40 -0
  61. package/lib/cjs/components/input-number/input-number.d.ts.map +1 -0
  62. package/lib/cjs/components/input-number/input-number.js +248 -0
  63. package/lib/cjs/components/input-number/input-number.js.map +1 -0
  64. package/lib/cjs/components/input-number/types.d.ts +30 -0
  65. package/lib/cjs/components/input-number/types.d.ts.map +1 -0
  66. package/lib/cjs/components/input-number/types.js +7 -0
  67. package/lib/cjs/components/input-number/types.js.map +1 -0
  68. package/lib/cjs/components/select/config.d.ts +1 -0
  69. package/lib/cjs/components/select/config.d.ts.map +1 -1
  70. package/lib/cjs/components/select/config.js +2 -1
  71. package/lib/cjs/components/select/config.js.map +1 -1
  72. package/lib/cjs/components/select/index.d.ts +1 -1
  73. package/lib/cjs/components/select/index.d.ts.map +1 -1
  74. package/lib/cjs/components/select/select.d.ts +8 -1
  75. package/lib/cjs/components/select/select.d.ts.map +1 -1
  76. package/lib/cjs/components/select/select.js +14 -1
  77. package/lib/cjs/components/select/select.js.map +1 -1
  78. package/lib/cjs/components/select/tags.d.ts.map +1 -1
  79. package/lib/cjs/components/select/tags.js +10 -0
  80. package/lib/cjs/components/select/tags.js.map +1 -1
  81. package/lib/cjs/index.d.ts +9 -1
  82. package/lib/cjs/index.d.ts.map +1 -1
  83. package/lib/cjs/index.js +11 -7
  84. package/lib/cjs/index.js.map +1 -1
  85. package/lib/cjs/init-all.d.ts +6 -0
  86. package/lib/cjs/init-all.d.ts.map +1 -0
  87. package/lib/cjs/init-all.js +17 -0
  88. package/lib/cjs/init-all.js.map +1 -0
  89. package/lib/cjs/legacy.d.ts +8 -0
  90. package/lib/cjs/legacy.d.ts.map +1 -0
  91. package/lib/cjs/legacy.js +26 -0
  92. package/lib/cjs/legacy.js.map +1 -0
  93. package/lib/esm/components/context-menu/context-menu.d.ts +66 -0
  94. package/lib/esm/components/context-menu/context-menu.d.ts.map +1 -0
  95. package/lib/esm/components/context-menu/context-menu.js +420 -0
  96. package/lib/esm/components/context-menu/context-menu.js.map +1 -0
  97. package/lib/esm/components/context-menu/index.d.ts +7 -0
  98. package/lib/esm/components/context-menu/index.d.ts.map +1 -0
  99. package/lib/esm/components/context-menu/index.js +6 -0
  100. package/lib/esm/components/context-menu/index.js.map +1 -0
  101. package/lib/esm/components/context-menu/types.d.ts +30 -0
  102. package/lib/esm/components/context-menu/types.d.ts.map +1 -0
  103. package/lib/esm/components/context-menu/types.js +6 -0
  104. package/lib/esm/components/context-menu/types.js.map +1 -0
  105. package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
  106. package/lib/esm/components/datatable/datatable-checkbox.js +34 -15
  107. package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
  108. package/lib/esm/components/datatable/datatable-contracts.d.ts +66 -0
  109. package/lib/esm/components/datatable/datatable-contracts.d.ts.map +1 -0
  110. package/lib/esm/components/datatable/datatable-contracts.js +6 -0
  111. package/lib/esm/components/datatable/datatable-contracts.js.map +1 -0
  112. package/lib/esm/components/datatable/datatable-event-adapter.d.ts +7 -0
  113. package/lib/esm/components/datatable/datatable-event-adapter.d.ts.map +1 -0
  114. package/lib/esm/components/datatable/datatable-event-adapter.js +13 -0
  115. package/lib/esm/components/datatable/datatable-event-adapter.js.map +1 -0
  116. package/lib/esm/components/datatable/datatable-local-provider.d.ts +25 -0
  117. package/lib/esm/components/datatable/datatable-local-provider.d.ts.map +1 -0
  118. package/lib/esm/components/datatable/datatable-local-provider.js +187 -0
  119. package/lib/esm/components/datatable/datatable-local-provider.js.map +1 -0
  120. package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts +15 -0
  121. package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts.map +1 -0
  122. package/lib/esm/components/datatable/datatable-pagination-renderer.js +141 -0
  123. package/lib/esm/components/datatable/datatable-pagination-renderer.js.map +1 -0
  124. package/lib/esm/components/datatable/datatable-remote-provider.d.ts +25 -0
  125. package/lib/esm/components/datatable/datatable-remote-provider.d.ts.map +1 -0
  126. package/lib/esm/components/datatable/datatable-remote-provider.js +188 -0
  127. package/lib/esm/components/datatable/datatable-remote-provider.js.map +1 -0
  128. package/lib/esm/components/datatable/datatable-state-store.d.ts +21 -0
  129. package/lib/esm/components/datatable/datatable-state-store.d.ts.map +1 -0
  130. package/lib/esm/components/datatable/datatable-state-store.js +78 -0
  131. package/lib/esm/components/datatable/datatable-state-store.js.map +1 -0
  132. package/lib/esm/components/datatable/datatable-table-renderer.d.ts +16 -0
  133. package/lib/esm/components/datatable/datatable-table-renderer.d.ts.map +1 -0
  134. package/lib/esm/components/datatable/datatable-table-renderer.js +138 -0
  135. package/lib/esm/components/datatable/datatable-table-renderer.js.map +1 -0
  136. package/lib/esm/components/datatable/datatable.d.ts +9 -87
  137. package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
  138. package/lib/esm/components/datatable/datatable.js +234 -740
  139. package/lib/esm/components/datatable/datatable.js.map +1 -1
  140. package/lib/esm/components/dropdown/dropdown.d.ts +2 -2
  141. package/lib/esm/components/dropdown/dropdown.d.ts.map +1 -1
  142. package/lib/esm/components/dropdown/dropdown.js +68 -31
  143. package/lib/esm/components/dropdown/dropdown.js.map +1 -1
  144. package/lib/esm/components/input-number/index.d.ts +7 -0
  145. package/lib/esm/components/input-number/index.d.ts.map +1 -0
  146. package/lib/esm/components/input-number/index.js +6 -0
  147. package/lib/esm/components/input-number/index.js.map +1 -0
  148. package/lib/esm/components/input-number/input-number.d.ts +40 -0
  149. package/lib/esm/components/input-number/input-number.d.ts.map +1 -0
  150. package/lib/esm/components/input-number/input-number.js +245 -0
  151. package/lib/esm/components/input-number/input-number.js.map +1 -0
  152. package/lib/esm/components/input-number/types.d.ts +30 -0
  153. package/lib/esm/components/input-number/types.d.ts.map +1 -0
  154. package/lib/esm/components/input-number/types.js +6 -0
  155. package/lib/esm/components/input-number/types.js.map +1 -0
  156. package/lib/esm/components/select/config.d.ts +1 -0
  157. package/lib/esm/components/select/config.d.ts.map +1 -1
  158. package/lib/esm/components/select/config.js +2 -1
  159. package/lib/esm/components/select/config.js.map +1 -1
  160. package/lib/esm/components/select/index.d.ts +1 -1
  161. package/lib/esm/components/select/index.d.ts.map +1 -1
  162. package/lib/esm/components/select/select.d.ts +8 -1
  163. package/lib/esm/components/select/select.d.ts.map +1 -1
  164. package/lib/esm/components/select/select.js +14 -1
  165. package/lib/esm/components/select/select.js.map +1 -1
  166. package/lib/esm/components/select/tags.d.ts.map +1 -1
  167. package/lib/esm/components/select/tags.js +11 -1
  168. package/lib/esm/components/select/tags.js.map +1 -1
  169. package/lib/esm/index.d.ts +9 -1
  170. package/lib/esm/index.d.ts.map +1 -1
  171. package/lib/esm/index.js +7 -5
  172. package/lib/esm/index.js.map +1 -1
  173. package/lib/esm/init-all.d.ts +6 -0
  174. package/lib/esm/init-all.d.ts.map +1 -0
  175. package/lib/esm/init-all.js +13 -0
  176. package/lib/esm/init-all.js.map +1 -0
  177. package/lib/esm/legacy.d.ts +8 -0
  178. package/lib/esm/legacy.d.ts.map +1 -0
  179. package/lib/esm/legacy.js +8 -0
  180. package/lib/esm/legacy.js.map +1 -0
  181. package/package.json +35 -11
  182. package/src/__tests__/entrypoints.test.ts +71 -0
  183. package/src/components/context-menu/__tests__/context-menu.test.ts +117 -0
  184. package/src/components/context-menu/context-menu.css +32 -0
  185. package/src/components/context-menu/context-menu.ts +529 -0
  186. package/src/components/context-menu/index.ts +10 -0
  187. package/src/components/context-menu/types.ts +32 -0
  188. package/src/components/datatable/__tests__/architecture-boundaries.test.ts +259 -0
  189. package/src/components/datatable/datatable-checkbox.ts +34 -23
  190. package/src/components/datatable/datatable-contracts.ts +96 -0
  191. package/src/components/datatable/datatable-event-adapter.ts +21 -0
  192. package/src/components/datatable/datatable-local-provider.ts +193 -0
  193. package/src/components/datatable/datatable-pagination-renderer.ts +225 -0
  194. package/src/components/datatable/datatable-remote-provider.ts +178 -0
  195. package/src/components/datatable/datatable-state-store.ts +94 -0
  196. package/src/components/datatable/datatable-table-renderer.ts +214 -0
  197. package/src/components/datatable/datatable.ts +250 -918
  198. package/src/components/dropdown/dropdown.ts +86 -58
  199. package/src/components/input/input-group.css +14 -1
  200. package/src/components/input-number/__tests__/input-number.test.ts +278 -0
  201. package/src/components/input-number/index.ts +11 -0
  202. package/src/components/input-number/input-number.ts +267 -0
  203. package/src/components/input-number/types.ts +32 -0
  204. package/src/components/select/__tests__/ux-behaviors.test.ts +72 -0
  205. package/src/components/select/config.ts +3 -1
  206. package/src/components/select/index.ts +1 -1
  207. package/src/components/select/select.css +23 -20
  208. package/src/components/select/select.ts +15 -1
  209. package/src/components/select/tags.ts +14 -1
  210. package/src/index.ts +18 -5
  211. package/src/init-all.ts +15 -0
  212. package/src/legacy.ts +9 -0
  213. package/styles.css +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keenthemes/ktui",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Free & Open-Source Tailwind UI Components by Keenthemes",
5
5
  "homepage": "https://ktui.io",
6
6
  "repository": {
@@ -52,9 +52,36 @@
52
52
  "tailwind clipboard"
53
53
  ],
54
54
  "author": "@keenthemes",
55
- "types": "lib/esm/index.d.ts",
56
- "main": "lib/cjs/index.js",
57
- "module": "lib/esm/index.js",
55
+ "types": "lib/esm/legacy.d.ts",
56
+ "main": "lib/cjs/legacy.js",
57
+ "module": "lib/esm/legacy.js",
58
+ "exports": {
59
+ ".": {
60
+ "types": "./lib/esm/legacy.d.ts",
61
+ "import": "./lib/esm/legacy.js",
62
+ "require": "./lib/cjs/legacy.js"
63
+ },
64
+ "./core": {
65
+ "types": "./lib/esm/index.d.ts",
66
+ "import": "./lib/esm/index.js",
67
+ "require": "./lib/cjs/index.js"
68
+ },
69
+ "./init-all": {
70
+ "types": "./lib/esm/init-all.d.ts",
71
+ "import": "./lib/esm/init-all.js",
72
+ "require": "./lib/cjs/init-all.js"
73
+ },
74
+ "./components/*": {
75
+ "types": "./lib/esm/components/*/index.d.ts",
76
+ "import": "./lib/esm/components/*/index.js",
77
+ "require": "./lib/cjs/components/*/index.js"
78
+ },
79
+ "./src/*": "./src/*",
80
+ "./lib/*": "./lib/*",
81
+ "./styles.css": "./styles.css",
82
+ "./dist/*": "./dist/*",
83
+ "./package.json": "./package.json"
84
+ },
58
85
  "license": "MIT",
59
86
  "files": [
60
87
  "dist",
@@ -94,19 +121,14 @@
94
121
  "publish:github": "npm publish"
95
122
  },
96
123
  "devDependencies": {
97
- "@babel/core": "^7.27.3",
98
- "@babel/preset-env": "^7.27.2",
99
124
  "@eslint/js": "^9.27.0",
100
125
  "@types/jsdom": "^21.1.7",
101
126
  "@types/node": "^22.15.23",
102
127
  "@vitest/ui": "^4.0.16",
103
- "autoprefixer": "^10.4.21",
104
- "babel-loader": "^10.0.0",
105
128
  "concurrently": "^9.1.2",
106
129
  "eslint": "^10.0.0",
107
130
  "eslint-plugin-prettier": "^5.4.0",
108
131
  "jsdom": "^25.0.1",
109
- "mini-svg-data-uri": "^1.4.4",
110
132
  "prettier": "^3.5.3",
111
133
  "source-map-loader": "^5.0.0",
112
134
  "tailwindcss": "^4.1.11",
@@ -116,14 +138,16 @@
116
138
  "typescript-eslint": "^8.18.0",
117
139
  "vitest": "^4.0.16",
118
140
  "webpack": "^5.99.9",
119
- "webpack-cli": "^6.0.1",
120
- "webpack-merge-and-include-globally": "^1.0.7"
141
+ "webpack-cli": "^6.0.1"
121
142
  },
122
143
  "dependencies": {
123
144
  "@popperjs/core": "^2.11.8"
124
145
  },
125
146
  "overrides": {
147
+ "brace-expansion": "^5.0.6",
148
+ "fast-uri": "^3.1.2",
126
149
  "minimatch": "^10.2.3",
150
+ "postcss": "^8.5.14",
127
151
  "rollup": "^4.59.0",
128
152
  "serialize-javascript": "^7.0.3",
129
153
  "terser-webpack-plugin": "^5.3.17"
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+
3
+ describe('KTUI entrypoints', () => {
4
+ beforeEach(() => {
5
+ vi.restoreAllMocks();
6
+ vi.resetModules();
7
+ });
8
+
9
+ it('component-level import does not initialize unrelated components', async () => {
10
+ const { KTModal } = await import('../components/modal');
11
+ const modalInitSpy = vi.spyOn(KTModal, 'init');
12
+ const coreModule = await import('../index');
13
+ const componentsInitSpy = vi.spyOn(coreModule.KTComponents, 'init');
14
+
15
+ await import('../components/toggle-password');
16
+
17
+ expect(modalInitSpy).not.toHaveBeenCalled();
18
+ expect(componentsInitSpy).not.toHaveBeenCalled();
19
+ });
20
+
21
+ it('core entrypoint import is side-effect-free', async () => {
22
+ const domModule = await import('../helpers/dom');
23
+ const readySpy = vi.spyOn(domModule.default, 'ready');
24
+
25
+ const coreModule = await import('../index');
26
+ const initSpy = vi.spyOn(coreModule.KTComponents, 'init');
27
+
28
+ expect(readySpy).not.toHaveBeenCalled();
29
+ expect(initSpy).not.toHaveBeenCalled();
30
+ });
31
+
32
+ it('init-all entrypoint initializes components explicitly', async () => {
33
+ const domModule = await import('../helpers/dom');
34
+ const readySpy = vi
35
+ .spyOn(domModule.default, 'ready')
36
+ .mockImplementation((callback) => {
37
+ callback();
38
+ });
39
+
40
+ const coreModule = await import('../index');
41
+ const initSpy = vi.spyOn(coreModule.KTComponents, 'init');
42
+
43
+ const initAllModule = await import('../init-all');
44
+
45
+ expect(readySpy).toHaveBeenCalledTimes(1);
46
+ expect(initSpy).toHaveBeenCalledTimes(1);
47
+
48
+ initAllModule.initAllComponents();
49
+ expect(readySpy).toHaveBeenCalledTimes(2);
50
+ expect(initSpy).toHaveBeenCalledTimes(2);
51
+ });
52
+
53
+ it('legacy root entrypoint preserves auto-init behavior', async () => {
54
+ const domModule = await import('../helpers/dom');
55
+ const readySpy = vi
56
+ .spyOn(domModule.default, 'ready')
57
+ .mockImplementation((callback) => {
58
+ callback();
59
+ });
60
+
61
+ const coreModule = await import('../index');
62
+ const initSpy = vi.spyOn(coreModule.KTComponents, 'init');
63
+
64
+ const legacyModule = await import('../legacy');
65
+
66
+ expect(initSpy).toHaveBeenCalled();
67
+ expect(readySpy).toHaveBeenCalled();
68
+ expect(legacyModule.default).toBe(coreModule.default);
69
+ expect(legacyModule.KTComponents).toBe(coreModule.KTComponents);
70
+ });
71
+ });
@@ -0,0 +1,117 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { KTContextMenu } from '../context-menu';
3
+
4
+ const mockDestroy = vi.fn();
5
+ const mockForceUpdate = vi.fn();
6
+
7
+ vi.mock('@popperjs/core', () => ({
8
+ createPopper: vi.fn(() => ({
9
+ destroy: mockDestroy,
10
+ forceUpdate: mockForceUpdate,
11
+ })),
12
+ }));
13
+
14
+ function waitForTransitions() {
15
+ return new Promise<void>((resolve) => {
16
+ setTimeout(() => resolve(), 5);
17
+ });
18
+ }
19
+
20
+ function createFixture() {
21
+ document.body.innerHTML = `
22
+ <div id="root" data-kt-context-menu="true">
23
+ <div id="trigger" data-kt-context-menu-trigger="true">target</div>
24
+ <div id="menu" data-kt-context-menu-menu="true" class="kt-context-menu hidden">
25
+ <button id="dismiss" data-kt-context-menu-dismiss="true">dismiss</button>
26
+ </div>
27
+ </div>
28
+ `;
29
+
30
+ return {
31
+ root: document.getElementById('root') as HTMLElement,
32
+ trigger: document.getElementById('trigger') as HTMLElement,
33
+ menu: document.getElementById('menu') as HTMLElement,
34
+ dismiss: document.getElementById('dismiss') as HTMLElement,
35
+ };
36
+ }
37
+
38
+ describe('KTContextMenu', () => {
39
+ beforeEach(() => {
40
+ document.body.innerHTML = '';
41
+ mockDestroy.mockClear();
42
+ mockForceUpdate.mockClear();
43
+ });
44
+
45
+ afterEach(() => {
46
+ document.body.innerHTML = '';
47
+ });
48
+
49
+ it('creates and retrieves an instance', () => {
50
+ const { root } = createFixture();
51
+ const instance = new KTContextMenu(root);
52
+ expect(instance.getElement()).toBe(root);
53
+ expect(KTContextMenu.getInstance(root)).toBe(instance);
54
+ });
55
+
56
+ it('opens from showAtEvent and prevents native menu by default', () => {
57
+ const { root } = createFixture();
58
+ const instance = new KTContextMenu(root);
59
+ const event = new MouseEvent('contextmenu', {
60
+ bubbles: true,
61
+ cancelable: true,
62
+ clientX: 100,
63
+ clientY: 120,
64
+ });
65
+ const preventDefaultSpy = vi.spyOn(event, 'preventDefault');
66
+ instance.showAtEvent(event);
67
+
68
+ expect(instance.isOpen()).toBe(true);
69
+ expect(preventDefaultSpy).toHaveBeenCalled();
70
+ });
71
+
72
+ it('hide closes an open menu', async () => {
73
+ const { root } = createFixture();
74
+ const instance = new KTContextMenu(root);
75
+
76
+ instance.showAt(60, 60);
77
+ expect(instance.isOpen()).toBe(true);
78
+ (instance as unknown as { _shownAt: number })._shownAt = Date.now() - 300;
79
+ (instance as unknown as { _isOpen: boolean })._isOpen = true;
80
+
81
+ instance.hide();
82
+ await waitForTransitions();
83
+ expect(instance.isOpen()).toBe(false);
84
+ });
85
+
86
+ it('toggleAtEvent toggles menu state', async () => {
87
+ const { root } = createFixture();
88
+ const instance = new KTContextMenu(root);
89
+
90
+ const openEvent = new MouseEvent('contextmenu', {
91
+ bubbles: true,
92
+ cancelable: true,
93
+ clientX: 30,
94
+ clientY: 30,
95
+ });
96
+ instance.toggleAtEvent(openEvent);
97
+ expect(instance.isOpen()).toBe(true);
98
+ (instance as unknown as { _shownAt: number })._shownAt = Date.now() - 300;
99
+ (instance as unknown as { _isOpen: boolean })._isOpen = true;
100
+
101
+ instance.toggleAtEvent(openEvent);
102
+ await waitForTransitions();
103
+ expect(instance.isOpen()).toBe(false);
104
+ });
105
+
106
+ it('reinit rebuilds instances for existing roots', () => {
107
+ const { root } = createFixture();
108
+ new KTContextMenu(root);
109
+ const first = KTContextMenu.getInstance(root);
110
+ expect(first).not.toBeNull();
111
+
112
+ KTContextMenu.reinit();
113
+ const second = KTContextMenu.getInstance(root);
114
+ expect(second).not.toBeNull();
115
+ expect(second).not.toBe(first);
116
+ });
117
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
3
+ * Copyright 2025 by Keenthemes Inc
4
+ */
5
+
6
+ @layer components {
7
+ .kt-context-menu {
8
+ @apply p-1.5 space-y-0.5 rounded-md shadow-md shadow-[rgba(0,0,0,0.05)] border border-border bg-popover text-popover-foreground;
9
+
10
+ &:not(.open) {
11
+ @apply hidden;
12
+ }
13
+ }
14
+
15
+ .kt-context-menu-sub {
16
+ @apply space-y-1 w-full;
17
+ }
18
+
19
+ .kt-context-menu-toggle {
20
+ @apply w-full flex items-center gap-x-2 py-1.5 px-2 rounded-md font-medium text-sm text-start cursor-pointer disabled:opacity-50 disabled:pointer-events-none;
21
+ @apply text-foreground hover:bg-accent hover:text-accent-foreground;
22
+ }
23
+
24
+ .kt-context-menu-link {
25
+ @apply w-full flex items-center gap-x-2 py-1.5 px-2 rounded-md font-medium text-sm text-start cursor-pointer disabled:opacity-50 disabled:pointer-events-none;
26
+ @apply text-foreground hover:bg-accent hover:text-accent-foreground;
27
+ }
28
+
29
+ .kt-context-menu-separator {
30
+ @apply h-px bg-border my-2.5 -mx-2 rtl:transform rtl:rotate-180;
31
+ }
32
+ }