@api-client/ui 0.5.39 → 0.5.41

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 (292) hide show
  1. package/build/src/elements/contextual-menu/{internals/ContextualMenu.d.ts → ContextualMenu.d.ts} +11 -6
  2. package/build/src/elements/contextual-menu/ContextualMenu.d.ts.map +1 -0
  3. package/build/src/elements/contextual-menu/{internals/ContextualMenu.js → ContextualMenu.js} +25 -3
  4. package/build/src/elements/contextual-menu/ContextualMenu.js.map +1 -0
  5. package/build/src/elements/contextual-menu/internals/types.d.ts +16 -7
  6. package/build/src/elements/contextual-menu/internals/types.d.ts.map +1 -1
  7. package/build/src/elements/contextual-menu/internals/types.js.map +1 -1
  8. package/build/tsconfig.tsbuildinfo +1 -0
  9. package/package.json +1 -1
  10. package/src/elements/contextual-menu/{internals/ContextualMenu.ts → ContextualMenu.ts} +31 -7
  11. package/src/elements/contextual-menu/internals/types.ts +17 -7
  12. package/.aiexclude +0 -3
  13. package/.cursor/rules/html-and-css-best-practices.mdc +0 -63
  14. package/.cursor/rules/lit-best-practices.mdc +0 -89
  15. package/.editorconfig +0 -29
  16. package/.github/CONTRIBUTING.md +0 -24
  17. package/.github/instructions/html-and-css-best-practices.instructions.md +0 -70
  18. package/.github/instructions/lit-best-practices.instructions.md +0 -90
  19. package/.github/release.yml +0 -14
  20. package/.github/stale.yml +0 -23
  21. package/.github/workflows/auto-release.yml +0 -182
  22. package/.github/workflows/release.yml +0 -82
  23. package/.prettierrc.js +0 -14
  24. package/.vscode/settings.json +0 -18
  25. package/RELEASE.md +0 -163
  26. package/RELEASE_SETUP.md +0 -235
  27. package/build/src/demo/DemoPage.d.ts +0 -81
  28. package/build/src/demo/DemoPage.d.ts.map +0 -1
  29. package/build/src/demo/DemoPage.js +0 -175
  30. package/build/src/demo/DemoPage.js.map +0 -1
  31. package/build/src/demo/DemoStyles.d.ts +0 -3
  32. package/build/src/demo/DemoStyles.d.ts.map +0 -1
  33. package/build/src/demo/DemoStyles.js +0 -60
  34. package/build/src/demo/DemoStyles.js.map +0 -1
  35. package/build/src/elements/contextual-menu/internals/ContextualMenu.d.ts.map +0 -1
  36. package/build/src/elements/contextual-menu/internals/ContextualMenu.js.map +0 -1
  37. package/build/test/elements/navigation/Navigation.test.d.ts +0 -3
  38. package/build/test/elements/navigation/Navigation.test.d.ts.map +0 -1
  39. package/build/test/elements/navigation/Navigation.test.js +0 -113
  40. package/build/test/elements/navigation/Navigation.test.js.map +0 -1
  41. package/commitlint.config.cjs +0 -2
  42. package/demo/elements/authorization/AuthPlugin.js +0 -57
  43. package/demo/elements/authorization/AuthProxy.js +0 -215
  44. package/demo/elements/authorization/api-key.html +0 -27
  45. package/demo/elements/authorization/api-key.ts +0 -44
  46. package/demo/elements/authorization/basic.html +0 -27
  47. package/demo/elements/authorization/basic.ts +0 -43
  48. package/demo/elements/authorization/bearer.html +0 -27
  49. package/demo/elements/authorization/bearer.ts +0 -43
  50. package/demo/elements/authorization/env.js +0 -8
  51. package/demo/elements/authorization/index.html +0 -44
  52. package/demo/elements/authorization/ntlm.html +0 -27
  53. package/demo/elements/authorization/ntlm.ts +0 -43
  54. package/demo/elements/authorization/oauth-authorize.html +0 -75
  55. package/demo/elements/authorization/oauth-authorize.ts +0 -40
  56. package/demo/elements/authorization/oauth-error.html +0 -18
  57. package/demo/elements/authorization/oauth-error.ts +0 -10
  58. package/demo/elements/authorization/oauth-popup.html +0 -36
  59. package/demo/elements/authorization/oauth2.html +0 -27
  60. package/demo/elements/authorization/oauth2.ts +0 -100
  61. package/demo/elements/authorization/oidc.html +0 -27
  62. package/demo/elements/authorization/oidc.ts +0 -139
  63. package/demo/elements/authorization/private.crt +0 -31
  64. package/demo/elements/authorization/private.csr +0 -28
  65. package/demo/elements/authorization/private.key +0 -51
  66. package/demo/elements/authorization/private.pem +0 -31
  67. package/demo/elements/authorization/redirect.html +0 -20
  68. package/demo/elements/authorization/ssl-commands.sh +0 -30
  69. package/demo/elements/authorization/ssl.conf +0 -24
  70. package/demo/elements/autocomplete/index.html +0 -64
  71. package/demo/elements/autocomplete/index.ts +0 -171
  72. package/demo/elements/code-editor/CodeEditorDemo.ts +0 -173
  73. package/demo/elements/code-editor/index.html +0 -19
  74. package/demo/elements/context-menu/DemoIcons.ts +0 -21
  75. package/demo/elements/context-menu/basic.html +0 -25
  76. package/demo/elements/context-menu/basic.ts +0 -119
  77. package/demo/elements/context-menu/custom-data.html +0 -25
  78. package/demo/elements/context-menu/custom-data.ts +0 -62
  79. package/demo/elements/context-menu/demo.css +0 -28
  80. package/demo/elements/context-menu/enabled-state.html +0 -25
  81. package/demo/elements/context-menu/enabled-state.ts +0 -73
  82. package/demo/elements/context-menu/icons.html +0 -25
  83. package/demo/elements/context-menu/icons.ts +0 -64
  84. package/demo/elements/context-menu/index.html +0 -43
  85. package/demo/elements/context-menu/nested.html +0 -25
  86. package/demo/elements/context-menu/nestedt.ts +0 -152
  87. package/demo/elements/context-menu/no-execute.html +0 -25
  88. package/demo/elements/context-menu/no-execute.ts +0 -134
  89. package/demo/elements/context-menu/radio-menu.html +0 -25
  90. package/demo/elements/context-menu/radio-menu.ts +0 -83
  91. package/demo/elements/context-menu/separators.html +0 -25
  92. package/demo/elements/context-menu/separators.ts +0 -172
  93. package/demo/elements/currency/index.html +0 -91
  94. package/demo/elements/currency/index.ts +0 -352
  95. package/demo/elements/environment/environment-editor.html +0 -20
  96. package/demo/elements/environment/environment-editor.ts +0 -49
  97. package/demo/elements/environment/index.html +0 -33
  98. package/demo/elements/environment/server-editor.html +0 -20
  99. package/demo/elements/environment/server-editor.ts +0 -67
  100. package/demo/elements/environment/variables-editor.html +0 -20
  101. package/demo/elements/environment/variables-editor.ts +0 -94
  102. package/demo/elements/har/har-viewer.html +0 -20
  103. package/demo/elements/har/har-viewer.ts +0 -76
  104. package/demo/elements/har/har1.har +0 -3044
  105. package/demo/elements/har/har2.json +0 -439
  106. package/demo/elements/har/index.html +0 -26
  107. package/demo/elements/highlight/example.md +0 -27
  108. package/demo/elements/highlight/index.html +0 -31
  109. package/demo/elements/highlight/marked-highlight.html +0 -132
  110. package/demo/elements/highlight/marked-highlight.ts +0 -22
  111. package/demo/elements/highlight/prism-highlight.html +0 -62
  112. package/demo/elements/highlight/prism-highlight.ts +0 -17
  113. package/demo/elements/http/body-editor.html +0 -17
  114. package/demo/elements/http/body-editor.ts +0 -115
  115. package/demo/elements/http/headers.html +0 -17
  116. package/demo/elements/http/headers.ts +0 -59
  117. package/demo/elements/http/http-assertions.html +0 -20
  118. package/demo/elements/http/http-assertions.ts +0 -89
  119. package/demo/elements/http/http-flows.html +0 -23
  120. package/demo/elements/http/http-flows.ts +0 -89
  121. package/demo/elements/http/index.html +0 -45
  122. package/demo/elements/http/request-editor.html +0 -26
  123. package/demo/elements/http/request-editor.ts +0 -197
  124. package/demo/elements/http/request-log.html +0 -16
  125. package/demo/elements/http/request-log.ts +0 -136
  126. package/demo/elements/http/url-editing.html +0 -17
  127. package/demo/elements/http/url-editing.ts +0 -112
  128. package/demo/elements/icons/index.html +0 -81
  129. package/demo/elements/icons/index.ts +0 -52
  130. package/demo/elements/index.html +0 -72
  131. package/demo/elements/mention-textarea/index.html +0 -19
  132. package/demo/elements/mention-textarea/index.ts +0 -205
  133. package/demo/elements/navigation/navigation-item.html +0 -49
  134. package/demo/elements/navigation/navigation-item.ts +0 -131
  135. package/demo/elements/navigation/navigation.html +0 -20
  136. package/demo/elements/navigation/navigation.ts +0 -45
  137. package/demo/elements/project/index.html +0 -29
  138. package/demo/elements/project/project-run-report.html +0 -20
  139. package/demo/elements/project/project-run-report.ts +0 -132
  140. package/demo/elements/project/request-editor.html +0 -23
  141. package/demo/elements/project/request-editor.ts +0 -232
  142. package/demo/elements/user/user-avatar.html +0 -17
  143. package/demo/elements/user/user-avatar.ts +0 -60
  144. package/demo/env.js +0 -4
  145. package/demo/index.html +0 -34
  146. package/demo/layout/index.html +0 -94
  147. package/demo/layout/index.ts +0 -190
  148. package/demo/md/DemoStyles.ts +0 -61
  149. package/demo/md/UiDemoPage.ts +0 -6
  150. package/demo/md/buttons/button.html +0 -121
  151. package/demo/md/buttons/button.ts +0 -246
  152. package/demo/md/buttons/group.html +0 -36
  153. package/demo/md/buttons/group.ts +0 -171
  154. package/demo/md/checkbox/index.html +0 -39
  155. package/demo/md/checkbox/index.ts +0 -220
  156. package/demo/md/chip/chip.html +0 -70
  157. package/demo/md/chip/chip.ts +0 -219
  158. package/demo/md/chip/pawel6c9a.jpg +0 -0
  159. package/demo/md/collapse/CustomDetail.ts +0 -89
  160. package/demo/md/collapse/collapse.html +0 -21
  161. package/demo/md/collapse/collapse.ts +0 -78
  162. package/demo/md/date-picker/date-picker.ts +0 -336
  163. package/demo/md/date-picker/index.html +0 -171
  164. package/demo/md/dialog/confirm-dialog.html +0 -49
  165. package/demo/md/dialog/confirm-dialog.ts +0 -121
  166. package/demo/md/dialog/dialog.html +0 -25
  167. package/demo/md/dialog/dialog.ts +0 -468
  168. package/demo/md/dropdown-list/index.html +0 -31
  169. package/demo/md/dropdown-list/index.ts +0 -158
  170. package/demo/md/icon-button/index.html +0 -122
  171. package/demo/md/icon-button/index.ts +0 -132
  172. package/demo/md/index.html +0 -73
  173. package/demo/md/inputs/input.html +0 -73
  174. package/demo/md/inputs/input.ts +0 -278
  175. package/demo/md/inputs/radio.html +0 -39
  176. package/demo/md/inputs/radio.ts +0 -156
  177. package/demo/md/inputs/switch.html +0 -45
  178. package/demo/md/inputs/switch.ts +0 -144
  179. package/demo/md/list/list.html +0 -65
  180. package/demo/md/list/list.ts +0 -204
  181. package/demo/md/listbox/listbox.html +0 -31
  182. package/demo/md/listbox/listbox.ts +0 -27
  183. package/demo/md/menu/index.html +0 -19
  184. package/demo/md/menu/index.ts +0 -514
  185. package/demo/md/notification/snack.html +0 -21
  186. package/demo/md/notification/snack.ts +0 -70
  187. package/demo/md/progress/progress.html +0 -46
  188. package/demo/md/progress/progress.ts +0 -161
  189. package/demo/md/segmented-button/index.html +0 -21
  190. package/demo/md/segmented-button/index.ts +0 -55
  191. package/demo/md/select/index.html +0 -16
  192. package/demo/md/select/index.ts +0 -217
  193. package/demo/md/tabs/tabs.html +0 -40
  194. package/demo/md/tabs/tabs.ts +0 -214
  195. package/demo/oauth-popup.html +0 -36
  196. package/demo/page.css +0 -8
  197. package/demo/resources/calendar-month.png +0 -0
  198. package/demo/resources/favorite.png +0 -0
  199. package/demo/resources/fingerprint.png +0 -0
  200. package/demo/resources/home-work.png +0 -0
  201. package/demo/resources/mood.png +0 -0
  202. package/demo/resources/print.png +0 -0
  203. package/demo/resources/stars.png +0 -0
  204. package/demo/resources/theaters.png +0 -0
  205. package/demo/tsconfig.json +0 -4
  206. package/eslint.config.js +0 -97
  207. package/scripts/copy-assets.js +0 -21
  208. package/scripts/release.js +0 -66
  209. package/src/demo/DemoPage.ts +0 -169
  210. package/src/demo/DemoStyles.ts +0 -60
  211. package/test/README.md +0 -375
  212. package/test/contextual-menu/ContextMenu.test.ts +0 -760
  213. package/test/contextual-menu/ContextMenuElement.test.ts +0 -569
  214. package/test/core/activity.spec.ts +0 -413
  215. package/test/core/activity_manager.spec.ts +0 -544
  216. package/test/core/application.spec.ts +0 -218
  217. package/test/core/fragment.spec.ts +0 -565
  218. package/test/core/fragment_manager.spec.ts +0 -404
  219. package/test/core/live_data.spec.ts +0 -558
  220. package/test/core/renderer.spec.ts +0 -113
  221. package/test/dom-assertions.test.ts +0 -182
  222. package/test/elements/MonacoSetup.ts +0 -65
  223. package/test/elements/authorization/basic-method.test.ts +0 -177
  224. package/test/elements/authorization/bearer-method.test.ts +0 -143
  225. package/test/elements/authorization/ntlm-method.test.ts +0 -219
  226. package/test/elements/authorization/oauth2-client-credentials-method.test.ts +0 -334
  227. package/test/elements/authorization/oauth2-code-method.test.ts +0 -320
  228. package/test/elements/authorization/oauth2-custom-grant-method.test.ts +0 -255
  229. package/test/elements/authorization/oauth2-device-code-method.test.ts +0 -371
  230. package/test/elements/authorization/oauth2-implicit-method.test.ts +0 -407
  231. package/test/elements/authorization/oauth2-jwt-method.test.ts +0 -217
  232. package/test/elements/authorization/oauth2-password-method.test.ts +0 -275
  233. package/test/elements/authorization/openid-method.test.ts +0 -591
  234. package/test/elements/autocomplete/autocomplete-input.spec.ts +0 -646
  235. package/test/elements/code-editor/code-editor.accessibility.test.ts +0 -298
  236. package/test/elements/code-editor/code-editor.test.ts +0 -574
  237. package/test/elements/currency/CurrencyPicker.accessibility.test.ts +0 -328
  238. package/test/elements/currency/CurrencyPicker.core.test.ts +0 -318
  239. package/test/elements/currency/CurrencyPicker.integration.test.ts +0 -482
  240. package/test/elements/currency/CurrencyPicker.test.ts +0 -486
  241. package/test/elements/data-table/DataTable.browser.test.ts +0 -649
  242. package/test/elements/har/HarUtils.test.ts +0 -45
  243. package/test/elements/har/HarViewerElement.test.ts +0 -687
  244. package/test/elements/har/test-data/har1.har +0 -3044
  245. package/test/elements/highlight/MarkedHighlightElement.test.ts +0 -452
  246. package/test/elements/highlight/PrismHighlightElement.test.ts +0 -79
  247. package/test/elements/highlight/PrismHighlighter.test.ts +0 -94
  248. package/test/elements/highlight/remoteSanitization.md +0 -1
  249. package/test/elements/highlight/test.md +0 -3
  250. package/test/elements/highlight/test1.md +0 -3
  251. package/test/elements/highlight/test2.md +0 -1
  252. package/test/elements/http/BodyFormdataEditorElement.test.ts +0 -482
  253. package/test/elements/http/BodyMultipartEditorElement.test.ts +0 -658
  254. package/test/elements/http/BodyRawEditorElement.test.ts +0 -90
  255. package/test/elements/http/CertificateAdd.test.ts +0 -457
  256. package/test/elements/http/HttpAssertions.test.ts +0 -994
  257. package/test/elements/http/HttpFlows.test.ts +0 -502
  258. package/test/elements/http/UrlEncodeUtils.test.ts +0 -202
  259. package/test/elements/layout/SplitItem.test.ts +0 -440
  260. package/test/elements/layout/SplitLayoutManager.test.ts +0 -1501
  261. package/test/elements/layout/SplitPanel.test.ts +0 -1109
  262. package/test/elements/mention-textarea/MentionTextArea.basic.test.ts +0 -114
  263. package/test/elements/mention-textarea/MentionTextArea.test.ts +0 -613
  264. package/test/elements/navigation/Navigation.test.ts +0 -120
  265. package/test/env.ts +0 -15
  266. package/test/events/EventTypes.test.ts +0 -363
  267. package/test/events/EventsTestHelpers.ts +0 -16
  268. package/test/helpers/TestUtils.ts +0 -243
  269. package/test/helpers/UiMock.ts +0 -185
  270. package/test/lib/Dom.test.ts +0 -231
  271. package/test/md/button/UiButton.test.ts +0 -347
  272. package/test/md/button/UiIconButton.test.ts +0 -155
  273. package/test/md/chip/UiChip.test.ts +0 -219
  274. package/test/md/collapse/UiCollapse.test.ts +0 -250
  275. package/test/md/collapse/flex-layout.test.ts +0 -105
  276. package/test/md/date-time/DateTime.test.ts +0 -348
  277. package/test/md/dialog/UiConfirmDialog.test.ts +0 -131
  278. package/test/md/dialog/UiDialog.test.ts +0 -759
  279. package/test/md/menu/Menu.test.ts +0 -855
  280. package/test/md/menu/MenuIntegration.test.ts +0 -426
  281. package/test/md/menu/MenuItem.test.ts +0 -652
  282. package/test/md/menu/SubMenu.test.ts +0 -410
  283. package/test/md/progress/UiCircularProgressElement.test.ts +0 -481
  284. package/test/md/progress/UiProgressElement.test.ts +0 -117
  285. package/test/md/progress/UiRangeElement.test.ts +0 -156
  286. package/test/md/select/Select.test.ts +0 -925
  287. package/test/plugins/takeScreenshotPlugin.js +0 -35
  288. package/test/setup.test.ts +0 -217
  289. package/test/setup.ts +0 -117
  290. package/test/tsconfig.json +0 -7
  291. package/web-dev-server.config.js +0 -21
  292. package/web-test-runner.config.js +0 -90
@@ -1,855 +0,0 @@
1
- import { assert, fixture, html, nextFrame, oneEvent } from '@open-wc/testing'
2
- import sinon from 'sinon'
3
- import Menu from '../../../src/md/menu/internal/Menu.js'
4
- import UiMenuItem from '../../../src/md/menu/internal/MenuItem.js'
5
- import UiSubMenu from '../../../src/md/menu/internal/SubMenu.js'
6
-
7
- import '../../../src/md/menu/ui-menu.js'
8
- import '../../../src/md/menu/ui-menu-item.js'
9
- import '../../../src/md/menu/ui-sub-menu.js'
10
- import '../../../src/md/icons/ui-icon.js'
11
- import '../../../src/md/button/ui-button.js'
12
-
13
- describe('md', () => {
14
- describe('Menu', () => {
15
- async function basicFixture(): Promise<Menu> {
16
- return fixture(html`
17
- <ui-menu id="test-menu">
18
- <ui-menu-item>Item 1</ui-menu-item>
19
- <ui-menu-item>Item 2</ui-menu-item>
20
- <ui-menu-item disabled>Item 3 (Disabled)</ui-menu-item>
21
- </ui-menu>
22
- `)
23
- }
24
-
25
- async function submenuFixture(): Promise<Menu> {
26
- return fixture(html`
27
- <ui-menu id="main-menu">
28
- <ui-menu-item id="file-item" submenu="file-submenu">
29
- <span slot="start"><ui-icon>folder</ui-icon></span>
30
- <span>File</span>
31
- </ui-menu-item>
32
- <ui-menu-item>Item 2</ui-menu-item>
33
-
34
- <ui-sub-menu id="file-submenu" anchor="file-item">
35
- <ui-menu-item>New File</ui-menu-item>
36
- <ui-menu-item>Open File</ui-menu-item>
37
- <ui-menu-item id="export-item" submenu="export-submenu">Export</ui-menu-item>
38
-
39
- <ui-sub-menu id="export-submenu" anchor="export-item">
40
- <ui-menu-item>Export as PDF</ui-menu-item>
41
- <ui-menu-item>Export as PNG</ui-menu-item>
42
- </ui-sub-menu>
43
- </ui-sub-menu>
44
- </ui-menu>
45
- `)
46
- }
47
-
48
- async function withTriggerFixture(): Promise<HTMLElement> {
49
- return fixture(html`
50
- <div>
51
- <ui-button id="trigger" popovertarget="menu">Open Menu</ui-button>
52
- <ui-menu id="menu">
53
- <ui-menu-item>Item 1</ui-menu-item>
54
- <ui-menu-item>Item 2</ui-menu-item>
55
- </ui-menu>
56
- </div>
57
- `)
58
- }
59
-
60
- describe('Basic functionality', () => {
61
- it('should create menu element', async () => {
62
- const element = await basicFixture()
63
- assert.instanceOf(element, Menu)
64
- assert.equal(element.tagName.toLowerCase(), 'ui-menu')
65
- })
66
-
67
- it('should have correct default properties', async () => {
68
- const element = await basicFixture()
69
- assert.isFalse(element.open)
70
- assert.isFalse(element.disabled)
71
- assert.isNull(element.activeSubMenu)
72
- })
73
-
74
- it('should set correct ARIA attributes', async () => {
75
- const element = await basicFixture()
76
- assert.equal(element.getAttribute('role'), 'menu')
77
- assert.equal(element.getAttribute('aria-expanded'), 'false')
78
- assert.equal(element.tabIndex, -1)
79
- })
80
-
81
- it('should set popover attribute if not present', async () => {
82
- const element = await basicFixture()
83
- assert.equal(element.getAttribute('popover'), 'auto')
84
- })
85
-
86
- it('should generate ID if not present', async () => {
87
- const element: Menu = await fixture(html`<ui-menu><ui-menu-item>Test</ui-menu-item></ui-menu>`)
88
- assert.isString(element.id)
89
- assert.isTrue(element.id.length > 0)
90
- })
91
- })
92
-
93
- describe('Show/Hide functionality', () => {
94
- it('should show menu', async () => {
95
- const element = await basicFixture()
96
- const showSpy = sinon.spy(element, 'showPopover')
97
-
98
- element.show()
99
- await nextFrame()
100
-
101
- assert.isTrue(element.open)
102
- assert.equal(element.getAttribute('aria-expanded'), 'true')
103
- assert.equal(element.tabIndex, 0)
104
- assert.isTrue(showSpy.calledOnce)
105
- })
106
-
107
- it('should hide menu', async () => {
108
- const element = await basicFixture()
109
- const hideSpy = sinon.spy(element, 'hidePopover')
110
-
111
- element.show()
112
- await nextFrame()
113
- element.hide()
114
- await nextFrame()
115
-
116
- assert.isFalse(element.open)
117
- assert.equal(element.getAttribute('aria-expanded'), 'false')
118
- assert.equal(element.tabIndex, -1)
119
- assert.isTrue(hideSpy.calledOnce)
120
- })
121
-
122
- it('should dispatch open event when shown', async () => {
123
- const element = await basicFixture()
124
-
125
- setTimeout(() => element.show())
126
- const event = await oneEvent(element, 'open')
127
-
128
- assert.instanceOf(event, CustomEvent)
129
- assert.isFalse(event.bubbles)
130
- assert.isTrue(event.composed)
131
- })
132
-
133
- it('should dispatch close event when hidden', async () => {
134
- const element = await basicFixture()
135
- element.show()
136
- await nextFrame()
137
-
138
- setTimeout(() => element.hide())
139
- const event = await oneEvent(element, 'close')
140
-
141
- assert.instanceOf(event, CustomEvent)
142
- assert.isFalse(event.bubbles)
143
- assert.isTrue(event.composed)
144
- })
145
- })
146
-
147
- describe('Popover integration', () => {
148
- it('should toggle popover state', async () => {
149
- const element = await basicFixture()
150
- const superToggleSpy = sinon.spy(Object.getPrototypeOf(Object.getPrototypeOf(element)), 'togglePopover')
151
-
152
- const result = element.togglePopover()
153
- await nextFrame()
154
-
155
- assert.isTrue(element.open)
156
- assert.equal(element.getAttribute('aria-expanded'), 'true')
157
- assert.equal(element.tabIndex, 0)
158
- assert.isTrue(superToggleSpy.calledOnce)
159
- assert.isTrue(result)
160
- })
161
-
162
- it('should handle beforetoggle event', async () => {
163
- const element = await basicFixture()
164
- element.show()
165
- await nextFrame()
166
-
167
- // Simulate beforetoggle event as if popover was closed externally
168
- const toggleEvent = Object.assign(new Event('beforetoggle'), {
169
- newState: 'closed',
170
- }) as ToggleEvent
171
-
172
- element.dispatchEvent(toggleEvent)
173
- await nextFrame()
174
-
175
- assert.isFalse(element.open)
176
- })
177
- })
178
-
179
- describe('Keyboard navigation', () => {
180
- it('should close menu on Escape key', async () => {
181
- const element = await basicFixture()
182
- element.show()
183
- await nextFrame()
184
-
185
- const event = new KeyboardEvent('keydown', { key: 'Escape' })
186
- element.dispatchEvent(event)
187
- await nextFrame()
188
-
189
- assert.isFalse(element.open)
190
- })
191
-
192
- it('should not handle keys when menu is closed', async () => {
193
- const element = await basicFixture()
194
- const hideSpy = sinon.spy(element, 'hide')
195
-
196
- const event = new KeyboardEvent('keydown', { key: 'Escape' })
197
- element.dispatchEvent(event)
198
- await nextFrame()
199
-
200
- assert.isFalse(hideSpy.called)
201
- })
202
-
203
- it('should open submenu on ArrowRight', async () => {
204
- const element = await submenuFixture()
205
- const menuItem = element.querySelector('#file-item') as UiMenuItem
206
- const openSubMenuSpy = sinon.spy(menuItem, 'openSubMenu')
207
-
208
- element.show()
209
- await nextFrame()
210
-
211
- // Set the active item first
212
- element.activeListItem = menuItem
213
-
214
- const event = new KeyboardEvent('keydown', { key: 'ArrowRight' })
215
- element.dispatchEvent(event)
216
-
217
- assert.isTrue(openSubMenuSpy.calledOnce)
218
- })
219
-
220
- it('should call closeSubMenu on ArrowLeft', async () => {
221
- const element = await submenuFixture()
222
- const closeSubMenuSpy = sinon.spy(element, 'closeSubMenu')
223
- element.show()
224
- await nextFrame()
225
-
226
- const event = new KeyboardEvent('keydown', { key: 'ArrowLeft' })
227
- element.dispatchEvent(event)
228
-
229
- assert.isTrue(closeSubMenuSpy.calledOnce)
230
- })
231
-
232
- it('should delegate other keys to parent UiList', async () => {
233
- const element = await basicFixture()
234
- element.show()
235
- await nextFrame()
236
-
237
- // Test that arrow down moves to next item (handled by parent UiList)
238
- const firstItem = element.querySelector('ui-menu-item') as UiMenuItem
239
- element.activeListItem = firstItem
240
-
241
- const event = new KeyboardEvent('keydown', { key: 'ArrowDown' })
242
- element.dispatchEvent(event)
243
- await nextFrame()
244
-
245
- // Verify that navigation occurred (the active item should have changed)
246
- // This tests the integration with the parent UiList keyboard handling
247
- assert.isNotNull(element.activeListItem)
248
- })
249
- })
250
-
251
- describe('Submenu management', () => {
252
- it('should handle submenu behavior through keyboard navigation', async () => {
253
- const element = await submenuFixture()
254
- const menuItem = element.querySelector('#file-item') as UiMenuItem
255
-
256
- element.show()
257
- await nextFrame()
258
-
259
- // Set active item and trigger submenu open via keyboard
260
- element.activeListItem = menuItem
261
- const rightArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowRight' })
262
- element.dispatchEvent(rightArrowEvent)
263
-
264
- // Check that submenu was opened
265
- await nextFrame()
266
- // The submenu should be set as active
267
- assert.isNotNull(element.activeSubMenu)
268
- })
269
-
270
- it('should handle submenu closing through keyboard navigation', async () => {
271
- const element = await submenuFixture()
272
- const submenu = element.querySelector('#file-submenu') as UiSubMenu
273
-
274
- element.show()
275
- await nextFrame()
276
-
277
- // Set active submenu
278
- element.setActiveSubMenu(submenu)
279
-
280
- // Close via keyboard
281
- const leftArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowLeft' })
282
- element.dispatchEvent(leftArrowEvent)
283
-
284
- assert.isNull(element.activeSubMenu)
285
- })
286
-
287
- it('should close active submenu', async () => {
288
- const element = await submenuFixture()
289
- const submenu = element.querySelector('#file-submenu') as UiSubMenu
290
- const hideSpy = sinon.spy(submenu, 'hide')
291
-
292
- element.setActiveSubMenu(submenu)
293
- element.closeSubMenu()
294
-
295
- assert.isTrue(hideSpy.calledOnce)
296
- assert.isNull(element.activeSubMenu)
297
- })
298
-
299
- it('should set active submenu and add event listener', async () => {
300
- const element = await submenuFixture()
301
- const submenu = element.querySelector('#file-submenu') as UiSubMenu
302
- const addListenerSpy = sinon.spy(submenu, 'addEventListener')
303
-
304
- element.setActiveSubMenu(submenu)
305
-
306
- assert.equal(element.activeSubMenu, submenu)
307
- assert.isTrue(addListenerSpy.calledWith('select'))
308
- })
309
-
310
- it('should handle submenu selection', async () => {
311
- const element = await submenuFixture()
312
- const submenu = element.querySelector('#file-submenu') as UiSubMenu
313
- let selectionHandled = false
314
-
315
- // Listen for selection on the main menu
316
- element.addEventListener('select', () => {
317
- selectionHandled = true
318
- })
319
-
320
- element.setActiveSubMenu(submenu)
321
-
322
- // Simulate submenu selection
323
- const selectEvent = new CustomEvent('select', {
324
- detail: { item: submenu.querySelector('ui-menu-item'), index: 0 },
325
- })
326
- submenu.dispatchEvent(selectEvent)
327
-
328
- assert.isTrue(selectionHandled)
329
- })
330
- })
331
-
332
- describe('Menu item selection', () => {
333
- it('should hide menu and notify selection', async () => {
334
- const element = await basicFixture()
335
- const menuItem = element.querySelector('ui-menu-item') as UiMenuItem
336
- const hideSpy = sinon.spy(element, 'hide')
337
- let selectionNotified = false
338
-
339
- // Listen for selection event instead of spying on protected method
340
- element.addEventListener('select', () => {
341
- selectionNotified = true
342
- })
343
-
344
- element.show()
345
- await nextFrame()
346
-
347
- element.notifySelect(menuItem, 0)
348
-
349
- assert.isTrue(hideSpy.calledOnce)
350
- assert.isTrue(selectionNotified)
351
- assert.isFalse(element.open)
352
- })
353
-
354
- it('should dispatch select event when menu item is selected', async () => {
355
- const element = await basicFixture()
356
- const menuItem = element.querySelector('ui-menu-item') as UiMenuItem
357
-
358
- element.show()
359
- await nextFrame()
360
-
361
- setTimeout(() => menuItem.click())
362
- const event = (await oneEvent(element, 'select')) as CustomEvent<{ item: UiMenuItem; index: number }>
363
-
364
- assert.instanceOf(event, CustomEvent)
365
- assert.equal(event.detail.item, menuItem)
366
- assert.equal(event.detail.index, 0)
367
- })
368
- })
369
-
370
- describe('Disabled state', () => {
371
- it('should set disabled attribute and call setDisabled', async () => {
372
- const element = await basicFixture()
373
-
374
- element.disabled = true
375
- await nextFrame()
376
-
377
- assert.isTrue(element.hasAttribute('disabled'))
378
- assert.isTrue(element.disabled)
379
- })
380
-
381
- it('should reflect disabled property to attribute', async () => {
382
- const element = await basicFixture()
383
-
384
- element.disabled = true
385
- await nextFrame()
386
-
387
- assert.equal(element.getAttribute('disabled'), '')
388
-
389
- element.disabled = false
390
- await nextFrame()
391
-
392
- assert.isFalse(element.hasAttribute('disabled'))
393
- })
394
- })
395
-
396
- describe('Slot changes', () => {
397
- it('should handle slot content changes', async () => {
398
- const element = await basicFixture()
399
-
400
- // Add a new menu item
401
- const newItem = document.createElement('ui-menu-item')
402
- newItem.textContent = 'New Item'
403
- element.appendChild(newItem)
404
-
405
- // Simulate slot change
406
- const slot = element.shadowRoot!.querySelector('slot')!
407
- slot.dispatchEvent(new Event('slotchange'))
408
-
409
- // Verify the new item is now part of the menu
410
- const menuItems = element.querySelectorAll('ui-menu-item')
411
- assert.equal(menuItems.length, 4) // 3 original + 1 new
412
- })
413
- })
414
-
415
- describe('Integration with popover trigger', () => {
416
- it('should work with popovertarget attribute', async () => {
417
- const container = await withTriggerFixture()
418
- const trigger = container.querySelector('#trigger') as HTMLElement
419
- const menu = container.querySelector('#menu') as Menu
420
-
421
- assert.equal(trigger.getAttribute('popovertarget'), 'menu')
422
- assert.equal(menu.id, 'menu')
423
-
424
- // Test that clicking trigger opens menu
425
- trigger.click()
426
- await nextFrame()
427
-
428
- assert.isTrue(menu.open)
429
- })
430
- })
431
-
432
- describe('Focus management', () => {
433
- it('should focus menu when shown', async () => {
434
- const element = await basicFixture()
435
- const focusSpy = sinon.spy(element, 'focus')
436
-
437
- element.show()
438
- await nextFrame()
439
-
440
- assert.isTrue(focusSpy.calledOnce)
441
- assert.equal(element.tabIndex, 0)
442
- })
443
-
444
- it('should set tabindex correctly based on open state', async () => {
445
- const element = await basicFixture()
446
-
447
- assert.equal(element.tabIndex, -1)
448
-
449
- element.show()
450
- await nextFrame()
451
-
452
- assert.equal(element.tabIndex, 0)
453
-
454
- element.hide()
455
- await nextFrame()
456
-
457
- assert.equal(element.tabIndex, -1)
458
- })
459
- })
460
-
461
- describe('Rendering', () => {
462
- it('should render slot for menu items', async () => {
463
- const element = await basicFixture()
464
- await nextFrame()
465
-
466
- const slot = element.shadowRoot!.querySelector('slot')
467
- assert.isNotNull(slot)
468
-
469
- const menuItems = element.querySelectorAll('ui-menu-item')
470
- assert.equal(menuItems.length, 3)
471
- })
472
-
473
- it('should render with menu-container class', async () => {
474
- const element = await basicFixture()
475
- await nextFrame()
476
-
477
- const container = element.shadowRoot!.querySelector('.menu-container')
478
- assert.isNotNull(container)
479
- })
480
- })
481
-
482
- describe('Edge cases', () => {
483
- it('should handle closeSubMenu when no submenu is active', async () => {
484
- const element = await basicFixture()
485
-
486
- // Should not throw
487
- element.closeSubMenu()
488
-
489
- assert.isNull(element.activeSubMenu)
490
- })
491
-
492
- it('should handle keydown events that are already prevented', async () => {
493
- const element = await basicFixture()
494
- const hideSpy = sinon.spy(element, 'hide')
495
- element.show()
496
- await nextFrame()
497
-
498
- const event = new KeyboardEvent('keydown', { key: 'Escape' })
499
- event.preventDefault()
500
- Object.defineProperty(event, 'defaultPrevented', { value: true })
501
-
502
- element.dispatchEvent(event)
503
-
504
- // Should not handle the event since it's already prevented
505
- assert.isFalse(hideSpy.called)
506
- })
507
- })
508
-
509
- describe('Menu item selection', () => {
510
- async function selectionFixture(): Promise<Menu> {
511
- return fixture(html`
512
- <ui-menu id="selection-menu">
513
- <ui-menu-item id="item1">Item 1</ui-menu-item>
514
- <ui-menu-item id="item2" selected>Item 2</ui-menu-item>
515
- <ui-menu-item id="item3">Item 3</ui-menu-item>
516
- <ui-menu-item id="item4" disabled>Item 4 (Disabled)</ui-menu-item>
517
- </ui-menu>
518
- `)
519
- }
520
-
521
- describe('selectedItem getter', () => {
522
- it('should return null when no item is selected', async () => {
523
- const element = await basicFixture()
524
- await nextFrame()
525
-
526
- assert.isNull(element.selectedItem)
527
- })
528
-
529
- it('should return the selected menu item', async () => {
530
- const element = await selectionFixture()
531
- await nextFrame()
532
-
533
- const selectedItem = element.selectedItem
534
- const item2 = element.querySelector('#item2') as UiMenuItem
535
-
536
- assert.isNotNull(selectedItem)
537
- assert.equal(selectedItem, item2)
538
- assert.isTrue(selectedItem!.selected)
539
- })
540
-
541
- it('should return the first selected item when multiple items are selected', async () => {
542
- const element = await selectionFixture()
543
- const item1 = element.querySelector('#item1') as UiMenuItem
544
- const item3 = element.querySelector('#item3') as UiMenuItem
545
- await nextFrame()
546
-
547
- // Manually set multiple items as selected
548
- item1.selected = true
549
- item3.selected = true
550
- await nextFrame()
551
-
552
- const selectedItem = element.selectedItem
553
- assert.equal(selectedItem, item1)
554
- })
555
- })
556
-
557
- describe('setSelectedItem method', () => {
558
- it('should select a menu item and clear previous selection', async () => {
559
- const element = await selectionFixture()
560
- const item1 = element.querySelector('#item1') as UiMenuItem
561
- const item2 = element.querySelector('#item2') as UiMenuItem
562
- await nextFrame()
563
-
564
- // Initially item2 is selected
565
- assert.isTrue(item2.selected)
566
- assert.isFalse(item1.selected)
567
-
568
- // Select item1
569
- element.setSelectedItem(item1)
570
- await nextFrame()
571
-
572
- assert.isTrue(item1.selected)
573
- assert.isFalse(item2.selected)
574
- assert.equal(element.selectedItem, item1)
575
- })
576
-
577
- it('should clear all selections when passed null', async () => {
578
- const element = await selectionFixture()
579
- const item2 = element.querySelector('#item2') as UiMenuItem
580
- await nextFrame()
581
-
582
- // Initially item2 is selected
583
- assert.isTrue(item2.selected)
584
-
585
- // Clear selection
586
- element.setSelectedItem(null)
587
- await nextFrame()
588
-
589
- assert.isFalse(item2.selected)
590
- assert.isNull(element.selectedItem)
591
- })
592
-
593
- it('should handle selecting disabled items', async () => {
594
- const element = await selectionFixture()
595
- const item4 = element.querySelector('#item4') as UiMenuItem
596
- await nextFrame()
597
-
598
- // Should be able to select disabled items programmatically
599
- element.setSelectedItem(item4)
600
- await nextFrame()
601
-
602
- assert.isTrue(item4.selected)
603
- assert.equal(element.selectedItem, item4)
604
- })
605
-
606
- it('should not throw when selecting an item not in the menu', async () => {
607
- const element = await selectionFixture()
608
- const externalItem: UiMenuItem = await fixture(html`<ui-menu-item>External Item</ui-menu-item>`)
609
- await nextFrame()
610
-
611
- // Should not throw
612
- element.setSelectedItem(externalItem)
613
-
614
- // External item should be selected but not affect the menu's selectedItem
615
- assert.isTrue(externalItem.selected)
616
- // The menu should return null since the external item is not in assignedMenuItems
617
- assert.isNull(element.selectedItem)
618
- })
619
- })
620
-
621
- describe('Selection clearing functionality', () => {
622
- it('should clear selection from all menu items when setting null', async () => {
623
- const element = await selectionFixture()
624
- const item1 = element.querySelector('#item1') as UiMenuItem
625
- const item2 = element.querySelector('#item2') as UiMenuItem
626
- const item3 = element.querySelector('#item3') as UiMenuItem
627
- await nextFrame()
628
-
629
- // Set multiple items as selected
630
- item1.selected = true
631
- item3.selected = true
632
- await nextFrame()
633
-
634
- // Initially item2 is selected from fixture, now item1 and item3 are also selected
635
- assert.isTrue(item1.selected)
636
- assert.isTrue(item2.selected)
637
- assert.isTrue(item3.selected)
638
-
639
- // Clear all selections using the public method
640
- element.setSelectedItem(null)
641
- await nextFrame()
642
-
643
- assert.isFalse(item1.selected)
644
- assert.isFalse(item2.selected)
645
- assert.isFalse(item3.selected)
646
- assert.isNull(element.selectedItem)
647
- })
648
-
649
- it('should clear previous selection when selecting new item', async () => {
650
- const element = await selectionFixture()
651
- const item1 = element.querySelector('#item1') as UiMenuItem
652
- const item2 = element.querySelector('#item2') as UiMenuItem
653
- const item3 = element.querySelector('#item3') as UiMenuItem
654
- await nextFrame()
655
-
656
- // Set multiple items as selected manually
657
- item1.selected = true
658
- item3.selected = true
659
- await nextFrame()
660
-
661
- // Select item2 - this should clear all other selections
662
- element.setSelectedItem(item2)
663
- await nextFrame()
664
-
665
- assert.isFalse(item1.selected)
666
- assert.isTrue(item2.selected)
667
- assert.isFalse(item3.selected)
668
- assert.equal(element.selectedItem, item2)
669
- })
670
-
671
- it('should clear selection when notifySelect is called with MenuItem', async () => {
672
- const element = await selectionFixture()
673
- const item1 = element.querySelector('#item1') as UiMenuItem
674
- const item2 = element.querySelector('#item2') as UiMenuItem
675
- const item3 = element.querySelector('#item3') as UiMenuItem
676
- await nextFrame()
677
-
678
- element.show()
679
- await nextFrame()
680
-
681
- // Set multiple items as selected manually
682
- item1.selected = true
683
- item3.selected = true
684
- await nextFrame()
685
-
686
- // Initially item2 is selected from fixture, now all items are selected
687
- assert.isTrue(item1.selected)
688
- assert.isTrue(item2.selected)
689
- assert.isTrue(item3.selected)
690
-
691
- // Call notifySelect on item1 - should clear all other selections
692
- element.notifySelect(item1, 0)
693
-
694
- assert.isTrue(item1.selected) // This one should remain selected
695
- assert.isFalse(item2.selected) // These should be cleared
696
- assert.isFalse(item3.selected)
697
- })
698
-
699
- it('should handle empty menu items', async () => {
700
- const element: Menu = await fixture(html`<ui-menu></ui-menu>`)
701
- await nextFrame()
702
-
703
- // Should not throw - test by setting and clearing selection
704
- element.setSelectedItem(null)
705
- assert.isNull(element.selectedItem)
706
- })
707
- })
708
-
709
- describe('notifySelect method', () => {
710
- it('should select menu item and hide menu', async () => {
711
- const element = await selectionFixture()
712
- const item1 = element.querySelector('#item1') as UiMenuItem
713
- const item2 = element.querySelector('#item2') as UiMenuItem
714
- await nextFrame()
715
-
716
- const hideSpy = sinon.spy(element, 'hide')
717
- element.show()
718
- await nextFrame()
719
-
720
- // Initially item2 is selected
721
- assert.isTrue(item2.selected)
722
- assert.isFalse(item1.selected)
723
-
724
- // Notify selection of item1
725
- const result = element.notifySelect(item1, 0)
726
-
727
- assert.isFalse(result) // Should return false (event not canceled)
728
- assert.isTrue(item1.selected)
729
- assert.isFalse(item2.selected) // Previous selection should be cleared
730
- assert.isTrue(hideSpy.calledOnce)
731
- })
732
-
733
- it('should handle non-MenuItem selection', async () => {
734
- const element = await selectionFixture()
735
- const nonMenuItem = document.createElement('div') as unknown as UiMenuItem
736
- await nextFrame()
737
-
738
- const hideSpy = sinon.spy(element, 'hide')
739
- element.show()
740
- await nextFrame()
741
-
742
- // Should not throw and should still hide menu
743
- // When item is not found in items array, notifySelect returns false
744
- const result = element.notifySelect(nonMenuItem, 0)
745
-
746
- assert.isFalse(result) // Returns false when item not found in items
747
- assert.isTrue(hideSpy.calledOnce)
748
- })
749
-
750
- it('should dispatch select event through parent class', async () => {
751
- const element = await selectionFixture()
752
- const item1 = element.querySelector('#item1') as UiMenuItem
753
- await nextFrame()
754
-
755
- element.show()
756
- await nextFrame()
757
-
758
- setTimeout(() => element.notifySelect(item1, 0))
759
- const event = await oneEvent(element, 'select')
760
-
761
- assert.instanceOf(event, CustomEvent)
762
- assert.equal((event as CustomEvent).detail.item, item1)
763
- assert.equal((event as CustomEvent).detail.index, 0)
764
- })
765
-
766
- it('should return true when select event is canceled', async () => {
767
- const element = await selectionFixture()
768
- const item1 = element.querySelector('#item1') as UiMenuItem
769
- await nextFrame()
770
-
771
- element.show()
772
- await nextFrame()
773
-
774
- // Add event listener that cancels the event
775
- element.addEventListener('select', (e) => {
776
- e.preventDefault()
777
- })
778
-
779
- const result = element.notifySelect(item1, 0)
780
-
781
- assert.isTrue(result) // Should return true when event is canceled
782
- assert.isTrue(item1.selected) // Item should still be selected in Menu
783
- })
784
-
785
- it('should clear selection from all items before selecting new one', async () => {
786
- const element = await selectionFixture()
787
- const item1 = element.querySelector('#item1') as UiMenuItem
788
- const item2 = element.querySelector('#item2') as UiMenuItem
789
- const item3 = element.querySelector('#item3') as UiMenuItem
790
- await nextFrame()
791
-
792
- // Manually set multiple items as selected
793
- item1.selected = true
794
- item3.selected = true
795
- await nextFrame()
796
-
797
- element.show()
798
- await nextFrame()
799
-
800
- // Notify selection of item2
801
- element.notifySelect(item2, 1)
802
-
803
- // Only item2 should be selected
804
- assert.isFalse(item1.selected)
805
- assert.isTrue(item2.selected)
806
- assert.isFalse(item3.selected)
807
- })
808
- })
809
-
810
- describe('Selection integration with keyboard navigation', () => {
811
- it('should maintain selection state when navigating with arrow keys', async () => {
812
- const element = await selectionFixture()
813
- const item2 = element.querySelector('#item2') as UiMenuItem
814
- await nextFrame()
815
-
816
- element.show()
817
- await nextFrame()
818
-
819
- // Initially item2 is selected
820
- assert.isTrue(item2.selected)
821
-
822
- // Navigate with arrow keys (should not affect selection)
823
- const downEvent = new KeyboardEvent('keydown', { key: 'ArrowDown' })
824
- element.dispatchEvent(downEvent)
825
- await nextFrame()
826
-
827
- // Selection should remain unchanged
828
- assert.isTrue(item2.selected)
829
- })
830
- })
831
-
832
- describe('Selection state preservation', () => {
833
- it('should preserve selection when menu is hidden and shown again', async () => {
834
- const element = await selectionFixture()
835
- const item2 = element.querySelector('#item2') as UiMenuItem
836
- await nextFrame()
837
-
838
- // Initially item2 is selected
839
- assert.isTrue(item2.selected)
840
- assert.equal(element.selectedItem, item2)
841
-
842
- // Show and hide menu
843
- element.show()
844
- await nextFrame()
845
- element.hide()
846
- await nextFrame()
847
-
848
- // Selection should be preserved
849
- assert.isTrue(item2.selected)
850
- assert.equal(element.selectedItem, item2)
851
- })
852
- })
853
- })
854
- })
855
- })