@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.
- package/build/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/.aiexclude +0 -3
- package/.cursor/rules/html-and-css-best-practices.mdc +0 -63
- package/.cursor/rules/lit-best-practices.mdc +0 -89
- package/.editorconfig +0 -29
- package/.github/CONTRIBUTING.md +0 -24
- package/.github/instructions/html-and-css-best-practices.instructions.md +0 -70
- package/.github/instructions/lit-best-practices.instructions.md +0 -90
- package/.github/release.yml +0 -14
- package/.github/stale.yml +0 -23
- package/.github/workflows/auto-release.yml +0 -182
- package/.github/workflows/release.yml +0 -82
- package/.prettierrc.js +0 -14
- package/.vscode/settings.json +0 -18
- package/RELEASE.md +0 -163
- package/RELEASE_SETUP.md +0 -235
- package/build/src/demo/DemoPage.d.ts +0 -81
- package/build/src/demo/DemoPage.d.ts.map +0 -1
- package/build/src/demo/DemoPage.js +0 -175
- package/build/src/demo/DemoPage.js.map +0 -1
- package/build/src/demo/DemoStyles.d.ts +0 -3
- package/build/src/demo/DemoStyles.d.ts.map +0 -1
- package/build/src/demo/DemoStyles.js +0 -60
- package/build/src/demo/DemoStyles.js.map +0 -1
- package/build/test/elements/navigation/Navigation.test.d.ts +0 -3
- package/build/test/elements/navigation/Navigation.test.d.ts.map +0 -1
- package/build/test/elements/navigation/Navigation.test.js +0 -113
- package/build/test/elements/navigation/Navigation.test.js.map +0 -1
- package/commitlint.config.cjs +0 -2
- package/demo/elements/authorization/AuthPlugin.js +0 -57
- package/demo/elements/authorization/AuthProxy.js +0 -215
- package/demo/elements/authorization/api-key.html +0 -27
- package/demo/elements/authorization/api-key.ts +0 -44
- package/demo/elements/authorization/basic.html +0 -27
- package/demo/elements/authorization/basic.ts +0 -43
- package/demo/elements/authorization/bearer.html +0 -27
- package/demo/elements/authorization/bearer.ts +0 -43
- package/demo/elements/authorization/env.js +0 -8
- package/demo/elements/authorization/index.html +0 -44
- package/demo/elements/authorization/ntlm.html +0 -27
- package/demo/elements/authorization/ntlm.ts +0 -43
- package/demo/elements/authorization/oauth-authorize.html +0 -75
- package/demo/elements/authorization/oauth-authorize.ts +0 -40
- package/demo/elements/authorization/oauth-error.html +0 -18
- package/demo/elements/authorization/oauth-error.ts +0 -10
- package/demo/elements/authorization/oauth-popup.html +0 -36
- package/demo/elements/authorization/oauth2.html +0 -27
- package/demo/elements/authorization/oauth2.ts +0 -100
- package/demo/elements/authorization/oidc.html +0 -27
- package/demo/elements/authorization/oidc.ts +0 -139
- package/demo/elements/authorization/private.crt +0 -31
- package/demo/elements/authorization/private.csr +0 -28
- package/demo/elements/authorization/private.key +0 -51
- package/demo/elements/authorization/private.pem +0 -31
- package/demo/elements/authorization/redirect.html +0 -20
- package/demo/elements/authorization/ssl-commands.sh +0 -30
- package/demo/elements/authorization/ssl.conf +0 -24
- package/demo/elements/autocomplete/index.html +0 -64
- package/demo/elements/autocomplete/index.ts +0 -171
- package/demo/elements/code-editor/CodeEditorDemo.ts +0 -173
- package/demo/elements/code-editor/index.html +0 -19
- package/demo/elements/context-menu/DemoIcons.ts +0 -21
- package/demo/elements/context-menu/basic.html +0 -25
- package/demo/elements/context-menu/basic.ts +0 -119
- package/demo/elements/context-menu/custom-data.html +0 -25
- package/demo/elements/context-menu/custom-data.ts +0 -62
- package/demo/elements/context-menu/demo.css +0 -28
- package/demo/elements/context-menu/enabled-state.html +0 -25
- package/demo/elements/context-menu/enabled-state.ts +0 -73
- package/demo/elements/context-menu/icons.html +0 -25
- package/demo/elements/context-menu/icons.ts +0 -64
- package/demo/elements/context-menu/index.html +0 -43
- package/demo/elements/context-menu/nested.html +0 -25
- package/demo/elements/context-menu/nestedt.ts +0 -152
- package/demo/elements/context-menu/no-execute.html +0 -25
- package/demo/elements/context-menu/no-execute.ts +0 -134
- package/demo/elements/context-menu/radio-menu.html +0 -25
- package/demo/elements/context-menu/radio-menu.ts +0 -83
- package/demo/elements/context-menu/separators.html +0 -25
- package/demo/elements/context-menu/separators.ts +0 -172
- package/demo/elements/currency/index.html +0 -91
- package/demo/elements/currency/index.ts +0 -352
- package/demo/elements/environment/environment-editor.html +0 -20
- package/demo/elements/environment/environment-editor.ts +0 -49
- package/demo/elements/environment/index.html +0 -33
- package/demo/elements/environment/server-editor.html +0 -20
- package/demo/elements/environment/server-editor.ts +0 -67
- package/demo/elements/environment/variables-editor.html +0 -20
- package/demo/elements/environment/variables-editor.ts +0 -94
- package/demo/elements/har/har-viewer.html +0 -20
- package/demo/elements/har/har-viewer.ts +0 -76
- package/demo/elements/har/har1.har +0 -3044
- package/demo/elements/har/har2.json +0 -439
- package/demo/elements/har/index.html +0 -26
- package/demo/elements/highlight/example.md +0 -27
- package/demo/elements/highlight/index.html +0 -31
- package/demo/elements/highlight/marked-highlight.html +0 -132
- package/demo/elements/highlight/marked-highlight.ts +0 -22
- package/demo/elements/highlight/prism-highlight.html +0 -62
- package/demo/elements/highlight/prism-highlight.ts +0 -17
- package/demo/elements/http/body-editor.html +0 -17
- package/demo/elements/http/body-editor.ts +0 -115
- package/demo/elements/http/headers.html +0 -17
- package/demo/elements/http/headers.ts +0 -59
- package/demo/elements/http/http-assertions.html +0 -20
- package/demo/elements/http/http-assertions.ts +0 -89
- package/demo/elements/http/http-flows.html +0 -23
- package/demo/elements/http/http-flows.ts +0 -89
- package/demo/elements/http/index.html +0 -45
- package/demo/elements/http/request-editor.html +0 -26
- package/demo/elements/http/request-editor.ts +0 -197
- package/demo/elements/http/request-log.html +0 -16
- package/demo/elements/http/request-log.ts +0 -136
- package/demo/elements/http/url-editing.html +0 -17
- package/demo/elements/http/url-editing.ts +0 -112
- package/demo/elements/icons/index.html +0 -81
- package/demo/elements/icons/index.ts +0 -52
- package/demo/elements/index.html +0 -72
- package/demo/elements/mention-textarea/index.html +0 -19
- package/demo/elements/mention-textarea/index.ts +0 -205
- package/demo/elements/navigation/navigation-item.html +0 -49
- package/demo/elements/navigation/navigation-item.ts +0 -131
- package/demo/elements/navigation/navigation.html +0 -20
- package/demo/elements/navigation/navigation.ts +0 -45
- package/demo/elements/project/index.html +0 -29
- package/demo/elements/project/project-run-report.html +0 -20
- package/demo/elements/project/project-run-report.ts +0 -132
- package/demo/elements/project/request-editor.html +0 -23
- package/demo/elements/project/request-editor.ts +0 -232
- package/demo/elements/user/user-avatar.html +0 -17
- package/demo/elements/user/user-avatar.ts +0 -60
- package/demo/env.js +0 -4
- package/demo/index.html +0 -34
- package/demo/layout/index.html +0 -94
- package/demo/layout/index.ts +0 -190
- package/demo/md/DemoStyles.ts +0 -61
- package/demo/md/UiDemoPage.ts +0 -6
- package/demo/md/buttons/button.html +0 -121
- package/demo/md/buttons/button.ts +0 -246
- package/demo/md/buttons/group.html +0 -36
- package/demo/md/buttons/group.ts +0 -171
- package/demo/md/checkbox/index.html +0 -39
- package/demo/md/checkbox/index.ts +0 -220
- package/demo/md/chip/chip.html +0 -70
- package/demo/md/chip/chip.ts +0 -219
- package/demo/md/chip/pawel6c9a.jpg +0 -0
- package/demo/md/collapse/CustomDetail.ts +0 -89
- package/demo/md/collapse/collapse.html +0 -21
- package/demo/md/collapse/collapse.ts +0 -78
- package/demo/md/date-picker/date-picker.ts +0 -336
- package/demo/md/date-picker/index.html +0 -171
- package/demo/md/dialog/confirm-dialog.html +0 -49
- package/demo/md/dialog/confirm-dialog.ts +0 -121
- package/demo/md/dialog/dialog.html +0 -25
- package/demo/md/dialog/dialog.ts +0 -468
- package/demo/md/dropdown-list/index.html +0 -31
- package/demo/md/dropdown-list/index.ts +0 -158
- package/demo/md/icon-button/index.html +0 -122
- package/demo/md/icon-button/index.ts +0 -132
- package/demo/md/index.html +0 -73
- package/demo/md/inputs/input.html +0 -73
- package/demo/md/inputs/input.ts +0 -278
- package/demo/md/inputs/radio.html +0 -39
- package/demo/md/inputs/radio.ts +0 -156
- package/demo/md/inputs/switch.html +0 -45
- package/demo/md/inputs/switch.ts +0 -144
- package/demo/md/list/list.html +0 -65
- package/demo/md/list/list.ts +0 -204
- package/demo/md/listbox/listbox.html +0 -31
- package/demo/md/listbox/listbox.ts +0 -27
- package/demo/md/menu/index.html +0 -19
- package/demo/md/menu/index.ts +0 -514
- package/demo/md/notification/snack.html +0 -21
- package/demo/md/notification/snack.ts +0 -70
- package/demo/md/progress/progress.html +0 -46
- package/demo/md/progress/progress.ts +0 -161
- package/demo/md/segmented-button/index.html +0 -21
- package/demo/md/segmented-button/index.ts +0 -55
- package/demo/md/select/index.html +0 -16
- package/demo/md/select/index.ts +0 -217
- package/demo/md/tabs/tabs.html +0 -40
- package/demo/md/tabs/tabs.ts +0 -214
- package/demo/oauth-popup.html +0 -36
- package/demo/page.css +0 -8
- package/demo/resources/calendar-month.png +0 -0
- package/demo/resources/favorite.png +0 -0
- package/demo/resources/fingerprint.png +0 -0
- package/demo/resources/home-work.png +0 -0
- package/demo/resources/mood.png +0 -0
- package/demo/resources/print.png +0 -0
- package/demo/resources/stars.png +0 -0
- package/demo/resources/theaters.png +0 -0
- package/demo/tsconfig.json +0 -4
- package/eslint.config.js +0 -97
- package/scripts/copy-assets.js +0 -21
- package/scripts/release.js +0 -66
- package/src/demo/DemoPage.ts +0 -169
- package/src/demo/DemoStyles.ts +0 -60
- package/test/README.md +0 -375
- package/test/contextual-menu/ContextMenu.test.ts +0 -760
- package/test/contextual-menu/ContextMenuElement.test.ts +0 -569
- package/test/core/activity.spec.ts +0 -413
- package/test/core/activity_manager.spec.ts +0 -544
- package/test/core/application.spec.ts +0 -218
- package/test/core/fragment.spec.ts +0 -565
- package/test/core/fragment_manager.spec.ts +0 -404
- package/test/core/live_data.spec.ts +0 -558
- package/test/core/renderer.spec.ts +0 -113
- package/test/dom-assertions.test.ts +0 -182
- package/test/elements/MonacoSetup.ts +0 -65
- package/test/elements/authorization/basic-method.test.ts +0 -177
- package/test/elements/authorization/bearer-method.test.ts +0 -143
- package/test/elements/authorization/ntlm-method.test.ts +0 -219
- package/test/elements/authorization/oauth2-client-credentials-method.test.ts +0 -334
- package/test/elements/authorization/oauth2-code-method.test.ts +0 -320
- package/test/elements/authorization/oauth2-custom-grant-method.test.ts +0 -255
- package/test/elements/authorization/oauth2-device-code-method.test.ts +0 -371
- package/test/elements/authorization/oauth2-implicit-method.test.ts +0 -407
- package/test/elements/authorization/oauth2-jwt-method.test.ts +0 -217
- package/test/elements/authorization/oauth2-password-method.test.ts +0 -275
- package/test/elements/authorization/openid-method.test.ts +0 -591
- package/test/elements/autocomplete/autocomplete-input.spec.ts +0 -646
- package/test/elements/code-editor/code-editor.accessibility.test.ts +0 -298
- package/test/elements/code-editor/code-editor.test.ts +0 -574
- package/test/elements/currency/CurrencyPicker.accessibility.test.ts +0 -328
- package/test/elements/currency/CurrencyPicker.core.test.ts +0 -318
- package/test/elements/currency/CurrencyPicker.integration.test.ts +0 -482
- package/test/elements/currency/CurrencyPicker.test.ts +0 -486
- package/test/elements/data-table/DataTable.browser.test.ts +0 -649
- package/test/elements/har/HarUtils.test.ts +0 -45
- package/test/elements/har/HarViewerElement.test.ts +0 -687
- package/test/elements/har/test-data/har1.har +0 -3044
- package/test/elements/highlight/MarkedHighlightElement.test.ts +0 -452
- package/test/elements/highlight/PrismHighlightElement.test.ts +0 -79
- package/test/elements/highlight/PrismHighlighter.test.ts +0 -94
- package/test/elements/highlight/remoteSanitization.md +0 -1
- package/test/elements/highlight/test.md +0 -3
- package/test/elements/highlight/test1.md +0 -3
- package/test/elements/highlight/test2.md +0 -1
- package/test/elements/http/BodyFormdataEditorElement.test.ts +0 -482
- package/test/elements/http/BodyMultipartEditorElement.test.ts +0 -658
- package/test/elements/http/BodyRawEditorElement.test.ts +0 -90
- package/test/elements/http/CertificateAdd.test.ts +0 -457
- package/test/elements/http/HttpAssertions.test.ts +0 -994
- package/test/elements/http/HttpFlows.test.ts +0 -502
- package/test/elements/http/UrlEncodeUtils.test.ts +0 -202
- package/test/elements/layout/SplitItem.test.ts +0 -440
- package/test/elements/layout/SplitLayoutManager.test.ts +0 -1501
- package/test/elements/layout/SplitPanel.test.ts +0 -1109
- package/test/elements/mention-textarea/MentionTextArea.basic.test.ts +0 -114
- package/test/elements/mention-textarea/MentionTextArea.test.ts +0 -613
- package/test/elements/navigation/Navigation.test.ts +0 -120
- package/test/env.ts +0 -15
- package/test/events/EventTypes.test.ts +0 -363
- package/test/events/EventsTestHelpers.ts +0 -16
- package/test/helpers/TestUtils.ts +0 -243
- package/test/helpers/UiMock.ts +0 -185
- package/test/lib/Dom.test.ts +0 -231
- package/test/md/button/UiButton.test.ts +0 -347
- package/test/md/button/UiIconButton.test.ts +0 -155
- package/test/md/chip/UiChip.test.ts +0 -219
- package/test/md/collapse/UiCollapse.test.ts +0 -250
- package/test/md/collapse/flex-layout.test.ts +0 -105
- package/test/md/date-time/DateTime.test.ts +0 -348
- package/test/md/dialog/UiConfirmDialog.test.ts +0 -131
- package/test/md/dialog/UiDialog.test.ts +0 -759
- package/test/md/menu/Menu.test.ts +0 -855
- package/test/md/menu/MenuIntegration.test.ts +0 -426
- package/test/md/menu/MenuItem.test.ts +0 -652
- package/test/md/menu/SubMenu.test.ts +0 -410
- package/test/md/progress/UiCircularProgressElement.test.ts +0 -481
- package/test/md/progress/UiProgressElement.test.ts +0 -117
- package/test/md/progress/UiRangeElement.test.ts +0 -156
- package/test/md/select/Select.test.ts +0 -925
- package/test/plugins/takeScreenshotPlugin.js +0 -35
- package/test/setup.test.ts +0 -217
- package/test/setup.ts +0 -117
- package/test/tsconfig.json +0 -7
- package/web-dev-server.config.js +0 -21
- 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
|
-
})
|