@api-client/ui 0.5.39 → 0.5.40

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 (281) hide show
  1. package/build/tsconfig.tsbuildinfo +1 -0
  2. package/package.json +1 -1
  3. package/.aiexclude +0 -3
  4. package/.cursor/rules/html-and-css-best-practices.mdc +0 -63
  5. package/.cursor/rules/lit-best-practices.mdc +0 -89
  6. package/.editorconfig +0 -29
  7. package/.github/CONTRIBUTING.md +0 -24
  8. package/.github/instructions/html-and-css-best-practices.instructions.md +0 -70
  9. package/.github/instructions/lit-best-practices.instructions.md +0 -90
  10. package/.github/release.yml +0 -14
  11. package/.github/stale.yml +0 -23
  12. package/.github/workflows/auto-release.yml +0 -182
  13. package/.github/workflows/release.yml +0 -82
  14. package/.prettierrc.js +0 -14
  15. package/.vscode/settings.json +0 -18
  16. package/RELEASE.md +0 -163
  17. package/RELEASE_SETUP.md +0 -235
  18. package/build/src/demo/DemoPage.d.ts +0 -81
  19. package/build/src/demo/DemoPage.d.ts.map +0 -1
  20. package/build/src/demo/DemoPage.js +0 -175
  21. package/build/src/demo/DemoPage.js.map +0 -1
  22. package/build/src/demo/DemoStyles.d.ts +0 -3
  23. package/build/src/demo/DemoStyles.d.ts.map +0 -1
  24. package/build/src/demo/DemoStyles.js +0 -60
  25. package/build/src/demo/DemoStyles.js.map +0 -1
  26. package/build/test/elements/navigation/Navigation.test.d.ts +0 -3
  27. package/build/test/elements/navigation/Navigation.test.d.ts.map +0 -1
  28. package/build/test/elements/navigation/Navigation.test.js +0 -113
  29. package/build/test/elements/navigation/Navigation.test.js.map +0 -1
  30. package/commitlint.config.cjs +0 -2
  31. package/demo/elements/authorization/AuthPlugin.js +0 -57
  32. package/demo/elements/authorization/AuthProxy.js +0 -215
  33. package/demo/elements/authorization/api-key.html +0 -27
  34. package/demo/elements/authorization/api-key.ts +0 -44
  35. package/demo/elements/authorization/basic.html +0 -27
  36. package/demo/elements/authorization/basic.ts +0 -43
  37. package/demo/elements/authorization/bearer.html +0 -27
  38. package/demo/elements/authorization/bearer.ts +0 -43
  39. package/demo/elements/authorization/env.js +0 -8
  40. package/demo/elements/authorization/index.html +0 -44
  41. package/demo/elements/authorization/ntlm.html +0 -27
  42. package/demo/elements/authorization/ntlm.ts +0 -43
  43. package/demo/elements/authorization/oauth-authorize.html +0 -75
  44. package/demo/elements/authorization/oauth-authorize.ts +0 -40
  45. package/demo/elements/authorization/oauth-error.html +0 -18
  46. package/demo/elements/authorization/oauth-error.ts +0 -10
  47. package/demo/elements/authorization/oauth-popup.html +0 -36
  48. package/demo/elements/authorization/oauth2.html +0 -27
  49. package/demo/elements/authorization/oauth2.ts +0 -100
  50. package/demo/elements/authorization/oidc.html +0 -27
  51. package/demo/elements/authorization/oidc.ts +0 -139
  52. package/demo/elements/authorization/private.crt +0 -31
  53. package/demo/elements/authorization/private.csr +0 -28
  54. package/demo/elements/authorization/private.key +0 -51
  55. package/demo/elements/authorization/private.pem +0 -31
  56. package/demo/elements/authorization/redirect.html +0 -20
  57. package/demo/elements/authorization/ssl-commands.sh +0 -30
  58. package/demo/elements/authorization/ssl.conf +0 -24
  59. package/demo/elements/autocomplete/index.html +0 -64
  60. package/demo/elements/autocomplete/index.ts +0 -171
  61. package/demo/elements/code-editor/CodeEditorDemo.ts +0 -173
  62. package/demo/elements/code-editor/index.html +0 -19
  63. package/demo/elements/context-menu/DemoIcons.ts +0 -21
  64. package/demo/elements/context-menu/basic.html +0 -25
  65. package/demo/elements/context-menu/basic.ts +0 -119
  66. package/demo/elements/context-menu/custom-data.html +0 -25
  67. package/demo/elements/context-menu/custom-data.ts +0 -62
  68. package/demo/elements/context-menu/demo.css +0 -28
  69. package/demo/elements/context-menu/enabled-state.html +0 -25
  70. package/demo/elements/context-menu/enabled-state.ts +0 -73
  71. package/demo/elements/context-menu/icons.html +0 -25
  72. package/demo/elements/context-menu/icons.ts +0 -64
  73. package/demo/elements/context-menu/index.html +0 -43
  74. package/demo/elements/context-menu/nested.html +0 -25
  75. package/demo/elements/context-menu/nestedt.ts +0 -152
  76. package/demo/elements/context-menu/no-execute.html +0 -25
  77. package/demo/elements/context-menu/no-execute.ts +0 -134
  78. package/demo/elements/context-menu/radio-menu.html +0 -25
  79. package/demo/elements/context-menu/radio-menu.ts +0 -83
  80. package/demo/elements/context-menu/separators.html +0 -25
  81. package/demo/elements/context-menu/separators.ts +0 -172
  82. package/demo/elements/currency/index.html +0 -91
  83. package/demo/elements/currency/index.ts +0 -352
  84. package/demo/elements/environment/environment-editor.html +0 -20
  85. package/demo/elements/environment/environment-editor.ts +0 -49
  86. package/demo/elements/environment/index.html +0 -33
  87. package/demo/elements/environment/server-editor.html +0 -20
  88. package/demo/elements/environment/server-editor.ts +0 -67
  89. package/demo/elements/environment/variables-editor.html +0 -20
  90. package/demo/elements/environment/variables-editor.ts +0 -94
  91. package/demo/elements/har/har-viewer.html +0 -20
  92. package/demo/elements/har/har-viewer.ts +0 -76
  93. package/demo/elements/har/har1.har +0 -3044
  94. package/demo/elements/har/har2.json +0 -439
  95. package/demo/elements/har/index.html +0 -26
  96. package/demo/elements/highlight/example.md +0 -27
  97. package/demo/elements/highlight/index.html +0 -31
  98. package/demo/elements/highlight/marked-highlight.html +0 -132
  99. package/demo/elements/highlight/marked-highlight.ts +0 -22
  100. package/demo/elements/highlight/prism-highlight.html +0 -62
  101. package/demo/elements/highlight/prism-highlight.ts +0 -17
  102. package/demo/elements/http/body-editor.html +0 -17
  103. package/demo/elements/http/body-editor.ts +0 -115
  104. package/demo/elements/http/headers.html +0 -17
  105. package/demo/elements/http/headers.ts +0 -59
  106. package/demo/elements/http/http-assertions.html +0 -20
  107. package/demo/elements/http/http-assertions.ts +0 -89
  108. package/demo/elements/http/http-flows.html +0 -23
  109. package/demo/elements/http/http-flows.ts +0 -89
  110. package/demo/elements/http/index.html +0 -45
  111. package/demo/elements/http/request-editor.html +0 -26
  112. package/demo/elements/http/request-editor.ts +0 -197
  113. package/demo/elements/http/request-log.html +0 -16
  114. package/demo/elements/http/request-log.ts +0 -136
  115. package/demo/elements/http/url-editing.html +0 -17
  116. package/demo/elements/http/url-editing.ts +0 -112
  117. package/demo/elements/icons/index.html +0 -81
  118. package/demo/elements/icons/index.ts +0 -52
  119. package/demo/elements/index.html +0 -72
  120. package/demo/elements/mention-textarea/index.html +0 -19
  121. package/demo/elements/mention-textarea/index.ts +0 -205
  122. package/demo/elements/navigation/navigation-item.html +0 -49
  123. package/demo/elements/navigation/navigation-item.ts +0 -131
  124. package/demo/elements/navigation/navigation.html +0 -20
  125. package/demo/elements/navigation/navigation.ts +0 -45
  126. package/demo/elements/project/index.html +0 -29
  127. package/demo/elements/project/project-run-report.html +0 -20
  128. package/demo/elements/project/project-run-report.ts +0 -132
  129. package/demo/elements/project/request-editor.html +0 -23
  130. package/demo/elements/project/request-editor.ts +0 -232
  131. package/demo/elements/user/user-avatar.html +0 -17
  132. package/demo/elements/user/user-avatar.ts +0 -60
  133. package/demo/env.js +0 -4
  134. package/demo/index.html +0 -34
  135. package/demo/layout/index.html +0 -94
  136. package/demo/layout/index.ts +0 -190
  137. package/demo/md/DemoStyles.ts +0 -61
  138. package/demo/md/UiDemoPage.ts +0 -6
  139. package/demo/md/buttons/button.html +0 -121
  140. package/demo/md/buttons/button.ts +0 -246
  141. package/demo/md/buttons/group.html +0 -36
  142. package/demo/md/buttons/group.ts +0 -171
  143. package/demo/md/checkbox/index.html +0 -39
  144. package/demo/md/checkbox/index.ts +0 -220
  145. package/demo/md/chip/chip.html +0 -70
  146. package/demo/md/chip/chip.ts +0 -219
  147. package/demo/md/chip/pawel6c9a.jpg +0 -0
  148. package/demo/md/collapse/CustomDetail.ts +0 -89
  149. package/demo/md/collapse/collapse.html +0 -21
  150. package/demo/md/collapse/collapse.ts +0 -78
  151. package/demo/md/date-picker/date-picker.ts +0 -336
  152. package/demo/md/date-picker/index.html +0 -171
  153. package/demo/md/dialog/confirm-dialog.html +0 -49
  154. package/demo/md/dialog/confirm-dialog.ts +0 -121
  155. package/demo/md/dialog/dialog.html +0 -25
  156. package/demo/md/dialog/dialog.ts +0 -468
  157. package/demo/md/dropdown-list/index.html +0 -31
  158. package/demo/md/dropdown-list/index.ts +0 -158
  159. package/demo/md/icon-button/index.html +0 -122
  160. package/demo/md/icon-button/index.ts +0 -132
  161. package/demo/md/index.html +0 -73
  162. package/demo/md/inputs/input.html +0 -73
  163. package/demo/md/inputs/input.ts +0 -278
  164. package/demo/md/inputs/radio.html +0 -39
  165. package/demo/md/inputs/radio.ts +0 -156
  166. package/demo/md/inputs/switch.html +0 -45
  167. package/demo/md/inputs/switch.ts +0 -144
  168. package/demo/md/list/list.html +0 -65
  169. package/demo/md/list/list.ts +0 -204
  170. package/demo/md/listbox/listbox.html +0 -31
  171. package/demo/md/listbox/listbox.ts +0 -27
  172. package/demo/md/menu/index.html +0 -19
  173. package/demo/md/menu/index.ts +0 -514
  174. package/demo/md/notification/snack.html +0 -21
  175. package/demo/md/notification/snack.ts +0 -70
  176. package/demo/md/progress/progress.html +0 -46
  177. package/demo/md/progress/progress.ts +0 -161
  178. package/demo/md/segmented-button/index.html +0 -21
  179. package/demo/md/segmented-button/index.ts +0 -55
  180. package/demo/md/select/index.html +0 -16
  181. package/demo/md/select/index.ts +0 -217
  182. package/demo/md/tabs/tabs.html +0 -40
  183. package/demo/md/tabs/tabs.ts +0 -214
  184. package/demo/oauth-popup.html +0 -36
  185. package/demo/page.css +0 -8
  186. package/demo/resources/calendar-month.png +0 -0
  187. package/demo/resources/favorite.png +0 -0
  188. package/demo/resources/fingerprint.png +0 -0
  189. package/demo/resources/home-work.png +0 -0
  190. package/demo/resources/mood.png +0 -0
  191. package/demo/resources/print.png +0 -0
  192. package/demo/resources/stars.png +0 -0
  193. package/demo/resources/theaters.png +0 -0
  194. package/demo/tsconfig.json +0 -4
  195. package/eslint.config.js +0 -97
  196. package/scripts/copy-assets.js +0 -21
  197. package/scripts/release.js +0 -66
  198. package/src/demo/DemoPage.ts +0 -169
  199. package/src/demo/DemoStyles.ts +0 -60
  200. package/test/README.md +0 -375
  201. package/test/contextual-menu/ContextMenu.test.ts +0 -760
  202. package/test/contextual-menu/ContextMenuElement.test.ts +0 -569
  203. package/test/core/activity.spec.ts +0 -413
  204. package/test/core/activity_manager.spec.ts +0 -544
  205. package/test/core/application.spec.ts +0 -218
  206. package/test/core/fragment.spec.ts +0 -565
  207. package/test/core/fragment_manager.spec.ts +0 -404
  208. package/test/core/live_data.spec.ts +0 -558
  209. package/test/core/renderer.spec.ts +0 -113
  210. package/test/dom-assertions.test.ts +0 -182
  211. package/test/elements/MonacoSetup.ts +0 -65
  212. package/test/elements/authorization/basic-method.test.ts +0 -177
  213. package/test/elements/authorization/bearer-method.test.ts +0 -143
  214. package/test/elements/authorization/ntlm-method.test.ts +0 -219
  215. package/test/elements/authorization/oauth2-client-credentials-method.test.ts +0 -334
  216. package/test/elements/authorization/oauth2-code-method.test.ts +0 -320
  217. package/test/elements/authorization/oauth2-custom-grant-method.test.ts +0 -255
  218. package/test/elements/authorization/oauth2-device-code-method.test.ts +0 -371
  219. package/test/elements/authorization/oauth2-implicit-method.test.ts +0 -407
  220. package/test/elements/authorization/oauth2-jwt-method.test.ts +0 -217
  221. package/test/elements/authorization/oauth2-password-method.test.ts +0 -275
  222. package/test/elements/authorization/openid-method.test.ts +0 -591
  223. package/test/elements/autocomplete/autocomplete-input.spec.ts +0 -646
  224. package/test/elements/code-editor/code-editor.accessibility.test.ts +0 -298
  225. package/test/elements/code-editor/code-editor.test.ts +0 -574
  226. package/test/elements/currency/CurrencyPicker.accessibility.test.ts +0 -328
  227. package/test/elements/currency/CurrencyPicker.core.test.ts +0 -318
  228. package/test/elements/currency/CurrencyPicker.integration.test.ts +0 -482
  229. package/test/elements/currency/CurrencyPicker.test.ts +0 -486
  230. package/test/elements/data-table/DataTable.browser.test.ts +0 -649
  231. package/test/elements/har/HarUtils.test.ts +0 -45
  232. package/test/elements/har/HarViewerElement.test.ts +0 -687
  233. package/test/elements/har/test-data/har1.har +0 -3044
  234. package/test/elements/highlight/MarkedHighlightElement.test.ts +0 -452
  235. package/test/elements/highlight/PrismHighlightElement.test.ts +0 -79
  236. package/test/elements/highlight/PrismHighlighter.test.ts +0 -94
  237. package/test/elements/highlight/remoteSanitization.md +0 -1
  238. package/test/elements/highlight/test.md +0 -3
  239. package/test/elements/highlight/test1.md +0 -3
  240. package/test/elements/highlight/test2.md +0 -1
  241. package/test/elements/http/BodyFormdataEditorElement.test.ts +0 -482
  242. package/test/elements/http/BodyMultipartEditorElement.test.ts +0 -658
  243. package/test/elements/http/BodyRawEditorElement.test.ts +0 -90
  244. package/test/elements/http/CertificateAdd.test.ts +0 -457
  245. package/test/elements/http/HttpAssertions.test.ts +0 -994
  246. package/test/elements/http/HttpFlows.test.ts +0 -502
  247. package/test/elements/http/UrlEncodeUtils.test.ts +0 -202
  248. package/test/elements/layout/SplitItem.test.ts +0 -440
  249. package/test/elements/layout/SplitLayoutManager.test.ts +0 -1501
  250. package/test/elements/layout/SplitPanel.test.ts +0 -1109
  251. package/test/elements/mention-textarea/MentionTextArea.basic.test.ts +0 -114
  252. package/test/elements/mention-textarea/MentionTextArea.test.ts +0 -613
  253. package/test/elements/navigation/Navigation.test.ts +0 -120
  254. package/test/env.ts +0 -15
  255. package/test/events/EventTypes.test.ts +0 -363
  256. package/test/events/EventsTestHelpers.ts +0 -16
  257. package/test/helpers/TestUtils.ts +0 -243
  258. package/test/helpers/UiMock.ts +0 -185
  259. package/test/lib/Dom.test.ts +0 -231
  260. package/test/md/button/UiButton.test.ts +0 -347
  261. package/test/md/button/UiIconButton.test.ts +0 -155
  262. package/test/md/chip/UiChip.test.ts +0 -219
  263. package/test/md/collapse/UiCollapse.test.ts +0 -250
  264. package/test/md/collapse/flex-layout.test.ts +0 -105
  265. package/test/md/date-time/DateTime.test.ts +0 -348
  266. package/test/md/dialog/UiConfirmDialog.test.ts +0 -131
  267. package/test/md/dialog/UiDialog.test.ts +0 -759
  268. package/test/md/menu/Menu.test.ts +0 -855
  269. package/test/md/menu/MenuIntegration.test.ts +0 -426
  270. package/test/md/menu/MenuItem.test.ts +0 -652
  271. package/test/md/menu/SubMenu.test.ts +0 -410
  272. package/test/md/progress/UiCircularProgressElement.test.ts +0 -481
  273. package/test/md/progress/UiProgressElement.test.ts +0 -117
  274. package/test/md/progress/UiRangeElement.test.ts +0 -156
  275. package/test/md/select/Select.test.ts +0 -925
  276. package/test/plugins/takeScreenshotPlugin.js +0 -35
  277. package/test/setup.test.ts +0 -217
  278. package/test/setup.ts +0 -117
  279. package/test/tsconfig.json +0 -7
  280. package/web-dev-server.config.js +0 -21
  281. 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
- })