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