@api-client/ui 0.5.39 → 0.5.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/build/tsconfig.tsbuildinfo +1 -0
  2. package/package.json +1 -1
  3. package/.aiexclude +0 -3
  4. package/.cursor/rules/html-and-css-best-practices.mdc +0 -63
  5. package/.cursor/rules/lit-best-practices.mdc +0 -89
  6. package/.editorconfig +0 -29
  7. package/.github/CONTRIBUTING.md +0 -24
  8. package/.github/instructions/html-and-css-best-practices.instructions.md +0 -70
  9. package/.github/instructions/lit-best-practices.instructions.md +0 -90
  10. package/.github/release.yml +0 -14
  11. package/.github/stale.yml +0 -23
  12. package/.github/workflows/auto-release.yml +0 -182
  13. package/.github/workflows/release.yml +0 -82
  14. package/.prettierrc.js +0 -14
  15. package/.vscode/settings.json +0 -18
  16. package/RELEASE.md +0 -163
  17. package/RELEASE_SETUP.md +0 -235
  18. package/build/src/demo/DemoPage.d.ts +0 -81
  19. package/build/src/demo/DemoPage.d.ts.map +0 -1
  20. package/build/src/demo/DemoPage.js +0 -175
  21. package/build/src/demo/DemoPage.js.map +0 -1
  22. package/build/src/demo/DemoStyles.d.ts +0 -3
  23. package/build/src/demo/DemoStyles.d.ts.map +0 -1
  24. package/build/src/demo/DemoStyles.js +0 -60
  25. package/build/src/demo/DemoStyles.js.map +0 -1
  26. package/build/test/elements/navigation/Navigation.test.d.ts +0 -3
  27. package/build/test/elements/navigation/Navigation.test.d.ts.map +0 -1
  28. package/build/test/elements/navigation/Navigation.test.js +0 -113
  29. package/build/test/elements/navigation/Navigation.test.js.map +0 -1
  30. package/commitlint.config.cjs +0 -2
  31. package/demo/elements/authorization/AuthPlugin.js +0 -57
  32. package/demo/elements/authorization/AuthProxy.js +0 -215
  33. package/demo/elements/authorization/api-key.html +0 -27
  34. package/demo/elements/authorization/api-key.ts +0 -44
  35. package/demo/elements/authorization/basic.html +0 -27
  36. package/demo/elements/authorization/basic.ts +0 -43
  37. package/demo/elements/authorization/bearer.html +0 -27
  38. package/demo/elements/authorization/bearer.ts +0 -43
  39. package/demo/elements/authorization/env.js +0 -8
  40. package/demo/elements/authorization/index.html +0 -44
  41. package/demo/elements/authorization/ntlm.html +0 -27
  42. package/demo/elements/authorization/ntlm.ts +0 -43
  43. package/demo/elements/authorization/oauth-authorize.html +0 -75
  44. package/demo/elements/authorization/oauth-authorize.ts +0 -40
  45. package/demo/elements/authorization/oauth-error.html +0 -18
  46. package/demo/elements/authorization/oauth-error.ts +0 -10
  47. package/demo/elements/authorization/oauth-popup.html +0 -36
  48. package/demo/elements/authorization/oauth2.html +0 -27
  49. package/demo/elements/authorization/oauth2.ts +0 -100
  50. package/demo/elements/authorization/oidc.html +0 -27
  51. package/demo/elements/authorization/oidc.ts +0 -139
  52. package/demo/elements/authorization/private.crt +0 -31
  53. package/demo/elements/authorization/private.csr +0 -28
  54. package/demo/elements/authorization/private.key +0 -51
  55. package/demo/elements/authorization/private.pem +0 -31
  56. package/demo/elements/authorization/redirect.html +0 -20
  57. package/demo/elements/authorization/ssl-commands.sh +0 -30
  58. package/demo/elements/authorization/ssl.conf +0 -24
  59. package/demo/elements/autocomplete/index.html +0 -64
  60. package/demo/elements/autocomplete/index.ts +0 -171
  61. package/demo/elements/code-editor/CodeEditorDemo.ts +0 -173
  62. package/demo/elements/code-editor/index.html +0 -19
  63. package/demo/elements/context-menu/DemoIcons.ts +0 -21
  64. package/demo/elements/context-menu/basic.html +0 -25
  65. package/demo/elements/context-menu/basic.ts +0 -119
  66. package/demo/elements/context-menu/custom-data.html +0 -25
  67. package/demo/elements/context-menu/custom-data.ts +0 -62
  68. package/demo/elements/context-menu/demo.css +0 -28
  69. package/demo/elements/context-menu/enabled-state.html +0 -25
  70. package/demo/elements/context-menu/enabled-state.ts +0 -73
  71. package/demo/elements/context-menu/icons.html +0 -25
  72. package/demo/elements/context-menu/icons.ts +0 -64
  73. package/demo/elements/context-menu/index.html +0 -43
  74. package/demo/elements/context-menu/nested.html +0 -25
  75. package/demo/elements/context-menu/nestedt.ts +0 -152
  76. package/demo/elements/context-menu/no-execute.html +0 -25
  77. package/demo/elements/context-menu/no-execute.ts +0 -134
  78. package/demo/elements/context-menu/radio-menu.html +0 -25
  79. package/demo/elements/context-menu/radio-menu.ts +0 -83
  80. package/demo/elements/context-menu/separators.html +0 -25
  81. package/demo/elements/context-menu/separators.ts +0 -172
  82. package/demo/elements/currency/index.html +0 -91
  83. package/demo/elements/currency/index.ts +0 -352
  84. package/demo/elements/environment/environment-editor.html +0 -20
  85. package/demo/elements/environment/environment-editor.ts +0 -49
  86. package/demo/elements/environment/index.html +0 -33
  87. package/demo/elements/environment/server-editor.html +0 -20
  88. package/demo/elements/environment/server-editor.ts +0 -67
  89. package/demo/elements/environment/variables-editor.html +0 -20
  90. package/demo/elements/environment/variables-editor.ts +0 -94
  91. package/demo/elements/har/har-viewer.html +0 -20
  92. package/demo/elements/har/har-viewer.ts +0 -76
  93. package/demo/elements/har/har1.har +0 -3044
  94. package/demo/elements/har/har2.json +0 -439
  95. package/demo/elements/har/index.html +0 -26
  96. package/demo/elements/highlight/example.md +0 -27
  97. package/demo/elements/highlight/index.html +0 -31
  98. package/demo/elements/highlight/marked-highlight.html +0 -132
  99. package/demo/elements/highlight/marked-highlight.ts +0 -22
  100. package/demo/elements/highlight/prism-highlight.html +0 -62
  101. package/demo/elements/highlight/prism-highlight.ts +0 -17
  102. package/demo/elements/http/body-editor.html +0 -17
  103. package/demo/elements/http/body-editor.ts +0 -115
  104. package/demo/elements/http/headers.html +0 -17
  105. package/demo/elements/http/headers.ts +0 -59
  106. package/demo/elements/http/http-assertions.html +0 -20
  107. package/demo/elements/http/http-assertions.ts +0 -89
  108. package/demo/elements/http/http-flows.html +0 -23
  109. package/demo/elements/http/http-flows.ts +0 -89
  110. package/demo/elements/http/index.html +0 -45
  111. package/demo/elements/http/request-editor.html +0 -26
  112. package/demo/elements/http/request-editor.ts +0 -197
  113. package/demo/elements/http/request-log.html +0 -16
  114. package/demo/elements/http/request-log.ts +0 -136
  115. package/demo/elements/http/url-editing.html +0 -17
  116. package/demo/elements/http/url-editing.ts +0 -112
  117. package/demo/elements/icons/index.html +0 -81
  118. package/demo/elements/icons/index.ts +0 -52
  119. package/demo/elements/index.html +0 -72
  120. package/demo/elements/mention-textarea/index.html +0 -19
  121. package/demo/elements/mention-textarea/index.ts +0 -205
  122. package/demo/elements/navigation/navigation-item.html +0 -49
  123. package/demo/elements/navigation/navigation-item.ts +0 -131
  124. package/demo/elements/navigation/navigation.html +0 -20
  125. package/demo/elements/navigation/navigation.ts +0 -45
  126. package/demo/elements/project/index.html +0 -29
  127. package/demo/elements/project/project-run-report.html +0 -20
  128. package/demo/elements/project/project-run-report.ts +0 -132
  129. package/demo/elements/project/request-editor.html +0 -23
  130. package/demo/elements/project/request-editor.ts +0 -232
  131. package/demo/elements/user/user-avatar.html +0 -17
  132. package/demo/elements/user/user-avatar.ts +0 -60
  133. package/demo/env.js +0 -4
  134. package/demo/index.html +0 -34
  135. package/demo/layout/index.html +0 -94
  136. package/demo/layout/index.ts +0 -190
  137. package/demo/md/DemoStyles.ts +0 -61
  138. package/demo/md/UiDemoPage.ts +0 -6
  139. package/demo/md/buttons/button.html +0 -121
  140. package/demo/md/buttons/button.ts +0 -246
  141. package/demo/md/buttons/group.html +0 -36
  142. package/demo/md/buttons/group.ts +0 -171
  143. package/demo/md/checkbox/index.html +0 -39
  144. package/demo/md/checkbox/index.ts +0 -220
  145. package/demo/md/chip/chip.html +0 -70
  146. package/demo/md/chip/chip.ts +0 -219
  147. package/demo/md/chip/pawel6c9a.jpg +0 -0
  148. package/demo/md/collapse/CustomDetail.ts +0 -89
  149. package/demo/md/collapse/collapse.html +0 -21
  150. package/demo/md/collapse/collapse.ts +0 -78
  151. package/demo/md/date-picker/date-picker.ts +0 -336
  152. package/demo/md/date-picker/index.html +0 -171
  153. package/demo/md/dialog/confirm-dialog.html +0 -49
  154. package/demo/md/dialog/confirm-dialog.ts +0 -121
  155. package/demo/md/dialog/dialog.html +0 -25
  156. package/demo/md/dialog/dialog.ts +0 -468
  157. package/demo/md/dropdown-list/index.html +0 -31
  158. package/demo/md/dropdown-list/index.ts +0 -158
  159. package/demo/md/icon-button/index.html +0 -122
  160. package/demo/md/icon-button/index.ts +0 -132
  161. package/demo/md/index.html +0 -73
  162. package/demo/md/inputs/input.html +0 -73
  163. package/demo/md/inputs/input.ts +0 -278
  164. package/demo/md/inputs/radio.html +0 -39
  165. package/demo/md/inputs/radio.ts +0 -156
  166. package/demo/md/inputs/switch.html +0 -45
  167. package/demo/md/inputs/switch.ts +0 -144
  168. package/demo/md/list/list.html +0 -65
  169. package/demo/md/list/list.ts +0 -204
  170. package/demo/md/listbox/listbox.html +0 -31
  171. package/demo/md/listbox/listbox.ts +0 -27
  172. package/demo/md/menu/index.html +0 -19
  173. package/demo/md/menu/index.ts +0 -514
  174. package/demo/md/notification/snack.html +0 -21
  175. package/demo/md/notification/snack.ts +0 -70
  176. package/demo/md/progress/progress.html +0 -46
  177. package/demo/md/progress/progress.ts +0 -161
  178. package/demo/md/segmented-button/index.html +0 -21
  179. package/demo/md/segmented-button/index.ts +0 -55
  180. package/demo/md/select/index.html +0 -16
  181. package/demo/md/select/index.ts +0 -217
  182. package/demo/md/tabs/tabs.html +0 -40
  183. package/demo/md/tabs/tabs.ts +0 -214
  184. package/demo/oauth-popup.html +0 -36
  185. package/demo/page.css +0 -8
  186. package/demo/resources/calendar-month.png +0 -0
  187. package/demo/resources/favorite.png +0 -0
  188. package/demo/resources/fingerprint.png +0 -0
  189. package/demo/resources/home-work.png +0 -0
  190. package/demo/resources/mood.png +0 -0
  191. package/demo/resources/print.png +0 -0
  192. package/demo/resources/stars.png +0 -0
  193. package/demo/resources/theaters.png +0 -0
  194. package/demo/tsconfig.json +0 -4
  195. package/eslint.config.js +0 -97
  196. package/scripts/copy-assets.js +0 -21
  197. package/scripts/release.js +0 -66
  198. package/src/demo/DemoPage.ts +0 -169
  199. package/src/demo/DemoStyles.ts +0 -60
  200. package/test/README.md +0 -375
  201. package/test/contextual-menu/ContextMenu.test.ts +0 -760
  202. package/test/contextual-menu/ContextMenuElement.test.ts +0 -569
  203. package/test/core/activity.spec.ts +0 -413
  204. package/test/core/activity_manager.spec.ts +0 -544
  205. package/test/core/application.spec.ts +0 -218
  206. package/test/core/fragment.spec.ts +0 -565
  207. package/test/core/fragment_manager.spec.ts +0 -404
  208. package/test/core/live_data.spec.ts +0 -558
  209. package/test/core/renderer.spec.ts +0 -113
  210. package/test/dom-assertions.test.ts +0 -182
  211. package/test/elements/MonacoSetup.ts +0 -65
  212. package/test/elements/authorization/basic-method.test.ts +0 -177
  213. package/test/elements/authorization/bearer-method.test.ts +0 -143
  214. package/test/elements/authorization/ntlm-method.test.ts +0 -219
  215. package/test/elements/authorization/oauth2-client-credentials-method.test.ts +0 -334
  216. package/test/elements/authorization/oauth2-code-method.test.ts +0 -320
  217. package/test/elements/authorization/oauth2-custom-grant-method.test.ts +0 -255
  218. package/test/elements/authorization/oauth2-device-code-method.test.ts +0 -371
  219. package/test/elements/authorization/oauth2-implicit-method.test.ts +0 -407
  220. package/test/elements/authorization/oauth2-jwt-method.test.ts +0 -217
  221. package/test/elements/authorization/oauth2-password-method.test.ts +0 -275
  222. package/test/elements/authorization/openid-method.test.ts +0 -591
  223. package/test/elements/autocomplete/autocomplete-input.spec.ts +0 -646
  224. package/test/elements/code-editor/code-editor.accessibility.test.ts +0 -298
  225. package/test/elements/code-editor/code-editor.test.ts +0 -574
  226. package/test/elements/currency/CurrencyPicker.accessibility.test.ts +0 -328
  227. package/test/elements/currency/CurrencyPicker.core.test.ts +0 -318
  228. package/test/elements/currency/CurrencyPicker.integration.test.ts +0 -482
  229. package/test/elements/currency/CurrencyPicker.test.ts +0 -486
  230. package/test/elements/data-table/DataTable.browser.test.ts +0 -649
  231. package/test/elements/har/HarUtils.test.ts +0 -45
  232. package/test/elements/har/HarViewerElement.test.ts +0 -687
  233. package/test/elements/har/test-data/har1.har +0 -3044
  234. package/test/elements/highlight/MarkedHighlightElement.test.ts +0 -452
  235. package/test/elements/highlight/PrismHighlightElement.test.ts +0 -79
  236. package/test/elements/highlight/PrismHighlighter.test.ts +0 -94
  237. package/test/elements/highlight/remoteSanitization.md +0 -1
  238. package/test/elements/highlight/test.md +0 -3
  239. package/test/elements/highlight/test1.md +0 -3
  240. package/test/elements/highlight/test2.md +0 -1
  241. package/test/elements/http/BodyFormdataEditorElement.test.ts +0 -482
  242. package/test/elements/http/BodyMultipartEditorElement.test.ts +0 -658
  243. package/test/elements/http/BodyRawEditorElement.test.ts +0 -90
  244. package/test/elements/http/CertificateAdd.test.ts +0 -457
  245. package/test/elements/http/HttpAssertions.test.ts +0 -994
  246. package/test/elements/http/HttpFlows.test.ts +0 -502
  247. package/test/elements/http/UrlEncodeUtils.test.ts +0 -202
  248. package/test/elements/layout/SplitItem.test.ts +0 -440
  249. package/test/elements/layout/SplitLayoutManager.test.ts +0 -1501
  250. package/test/elements/layout/SplitPanel.test.ts +0 -1109
  251. package/test/elements/mention-textarea/MentionTextArea.basic.test.ts +0 -114
  252. package/test/elements/mention-textarea/MentionTextArea.test.ts +0 -613
  253. package/test/elements/navigation/Navigation.test.ts +0 -120
  254. package/test/env.ts +0 -15
  255. package/test/events/EventTypes.test.ts +0 -363
  256. package/test/events/EventsTestHelpers.ts +0 -16
  257. package/test/helpers/TestUtils.ts +0 -243
  258. package/test/helpers/UiMock.ts +0 -185
  259. package/test/lib/Dom.test.ts +0 -231
  260. package/test/md/button/UiButton.test.ts +0 -347
  261. package/test/md/button/UiIconButton.test.ts +0 -155
  262. package/test/md/chip/UiChip.test.ts +0 -219
  263. package/test/md/collapse/UiCollapse.test.ts +0 -250
  264. package/test/md/collapse/flex-layout.test.ts +0 -105
  265. package/test/md/date-time/DateTime.test.ts +0 -348
  266. package/test/md/dialog/UiConfirmDialog.test.ts +0 -131
  267. package/test/md/dialog/UiDialog.test.ts +0 -759
  268. package/test/md/menu/Menu.test.ts +0 -855
  269. package/test/md/menu/MenuIntegration.test.ts +0 -426
  270. package/test/md/menu/MenuItem.test.ts +0 -652
  271. package/test/md/menu/SubMenu.test.ts +0 -410
  272. package/test/md/progress/UiCircularProgressElement.test.ts +0 -481
  273. package/test/md/progress/UiProgressElement.test.ts +0 -117
  274. package/test/md/progress/UiRangeElement.test.ts +0 -156
  275. package/test/md/select/Select.test.ts +0 -925
  276. package/test/plugins/takeScreenshotPlugin.js +0 -35
  277. package/test/setup.test.ts +0 -217
  278. package/test/setup.ts +0 -117
  279. package/test/tsconfig.json +0 -7
  280. package/web-dev-server.config.js +0 -21
  281. package/web-test-runner.config.js +0 -90
@@ -1,759 +0,0 @@
1
- import { assert, fixture, html } from '@open-wc/testing'
2
- import sinon from 'sinon'
3
- import UiDialog, { UiDialogClosingReason } from '../../../src/md/dialog/internals/Dialog.js'
4
- import { UiMock } from '../../helpers/UiMock.js'
5
- import UiButton from '../../../src/md/button/internals/button.js'
6
-
7
- import '../../../src/md/dialog/ui-dialog.js'
8
- import '../../../src/md/icons/ui-icon.js'
9
- import '../../../src/md/button/ui-button.js'
10
-
11
- describe('md', () => {
12
- describe('Dialog', () => {
13
- async function basicFixture(): Promise<UiDialog> {
14
- return fixture(html` <ui-dialog> Content </ui-dialog>`)
15
- }
16
-
17
- async function modalFixture(): Promise<UiDialog> {
18
- return fixture(html` <ui-dialog modal> Content </ui-dialog>`)
19
- }
20
-
21
- async function iconFixture(): Promise<UiDialog> {
22
- return fixture(
23
- html` <ui-dialog>
24
- <ui-icon slot="icon" icon="deleteOutline"></ui-icon>
25
- Content
26
- </ui-dialog>`
27
- )
28
- }
29
-
30
- async function titleFixture(): Promise<UiDialog> {
31
- return fixture(
32
- html` <ui-dialog>
33
- <span slot="title">The title</span>
34
- Content
35
- </ui-dialog>`
36
- )
37
- }
38
-
39
- async function buttonFixture(): Promise<UiDialog> {
40
- return fixture(
41
- html` <ui-dialog>
42
- Content
43
- <ui-button color="text" slot="button">Learn more</ui-button>
44
- <ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
45
- <ui-button color="text" slot="button" value="confirm">Accept</ui-button>
46
- </ui-dialog>`
47
- )
48
- }
49
-
50
- describe('open/close', () => {
51
- it('opens the native dialog via the "open" attribute', async () => {
52
- const element = await basicFixture()
53
- assert.isFalse(element.dialog.open, 'native dialog is closed initially')
54
-
55
- element.open = true
56
- await element.updateComplete
57
- assert.isTrue(element.dialog.open, 'native dialog is opened')
58
-
59
- element.open = false
60
- await element.updateComplete
61
- assert.isFalse(element.dialog.open, 'native dialog is closed again')
62
- })
63
-
64
- it('closes the dialog via the Escape button', async () => {
65
- const element = await buttonFixture()
66
- // the dialog requires a focusable element
67
- const button = element.querySelector('ui-button')!
68
- button.focus()
69
- await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
70
- assert.equal(element.open, false)
71
- })
72
-
73
- it('closes the dialog via the dismiss slotted button', async () => {
74
- const element = await buttonFixture()
75
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
76
- button.click()
77
- assert.equal(element.open, false)
78
- })
79
-
80
- it('closes the dialog via the confirm slotted button', async () => {
81
- const element = await buttonFixture()
82
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
83
- button.click()
84
- assert.equal(element.open, false)
85
- })
86
-
87
- it('closes the dialog via the dismissLabel button', async () => {
88
- const element = await basicFixture()
89
- element.dismissLabel = 'Close'
90
- await element.updateComplete
91
- const button = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
92
- button.click()
93
- assert.equal(element.open, false)
94
- })
95
-
96
- it('closes the dialog via the confirmLabel button', async () => {
97
- const element = await basicFixture()
98
- element.confirmLabel = 'Close'
99
- await element.updateComplete
100
- const button = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
101
- button.click()
102
- assert.equal(element.open, false)
103
- })
104
-
105
- it('dispatches the close event with cancelled = true', async () => {
106
- const element = await buttonFixture()
107
- const spy = sinon.spy()
108
- element.addEventListener('close', spy)
109
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
110
- button.click()
111
- assert.isTrue(spy.calledOnce, 'the event was dispatched')
112
- const event = spy.args[0][0] as CustomEvent<UiDialogClosingReason>
113
- assert.isTrue(event.detail.cancelled, 'the cancelled flag is set')
114
- })
115
-
116
- it('dispatches the close event with cancelled = true', async () => {
117
- const element = await buttonFixture()
118
- const spy = sinon.spy()
119
- element.addEventListener('close', spy)
120
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
121
- button.click()
122
- assert.isTrue(spy.calledOnce, 'the event was dispatched')
123
- const event = spy.args[0][0] as CustomEvent<UiDialogClosingReason>
124
- assert.isFalse(event.detail.cancelled, 'the cancelled flag is not set')
125
- })
126
-
127
- it('dispatches the dialogValue', async () => {
128
- const element = await buttonFixture()
129
- element.dialogValue = 'test'
130
- const spy = sinon.spy()
131
- element.addEventListener('close', spy)
132
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
133
- button.click()
134
- assert.isTrue(spy.calledOnce, 'the event was dispatched')
135
- const event = spy.args[0][0] as CustomEvent<UiDialogClosingReason>
136
- assert.equal(event.detail.value, 'test', 'has the value')
137
- })
138
- })
139
-
140
- describe('modal dialog', () => {
141
- it('opens the dialog as modal', async () => {
142
- const element = await modalFixture()
143
- const spy = sinon.spy(element.dialog, 'showModal')
144
- element.open = true
145
- await element.updateComplete
146
- assert.isTrue(spy.calledOnce)
147
- })
148
-
149
- it('applies modal class to dialog when modal is true', async () => {
150
- const element = await basicFixture()
151
- element.modal = true
152
- await element.updateComplete
153
-
154
- const dialog = element.shadowRoot!.querySelector('dialog') as HTMLDialogElement
155
- assert.ok(dialog, 'has the dialog element')
156
- assert.isTrue(dialog.classList.contains('modal'), 'has modal class')
157
- })
158
-
159
- it('applies non-modal class to dialog when modal is false', async () => {
160
- const element = await basicFixture()
161
- element.modal = false
162
- await element.updateComplete
163
-
164
- const dialog = element.shadowRoot!.querySelector('dialog') as HTMLDialogElement
165
- assert.ok(dialog, 'has the dialog element')
166
- assert.isTrue(dialog.classList.contains('non-modal'), 'has non-modal class')
167
- })
168
- })
169
-
170
- describe('icon', () => {
171
- it('renders the icon slot', async () => {
172
- const element = await basicFixture()
173
- const slot = element.shadowRoot!.querySelector('slot[name="icon"]') as HTMLSlotElement
174
- assert.ok(slot, 'has the slot')
175
- })
176
-
177
- it('does not render padding around the icon slot', async () => {
178
- const element = await basicFixture()
179
- const container = element.shadowRoot!.querySelector('.icon') as HTMLElement
180
- assert.isFalse(container.classList.contains('with-icon'), 'has no with-icon class')
181
- })
182
-
183
- it('renders padding around the icon slot with an icon', async () => {
184
- const element = await iconFixture()
185
- const container = element.shadowRoot!.querySelector('.icon') as HTMLElement
186
- assert.isTrue(container.classList.contains('with-icon'), 'has the with-icon class')
187
- })
188
- })
189
-
190
- describe('title', () => {
191
- it('renders the title slot', async () => {
192
- const element = await basicFixture()
193
- const slot = element.shadowRoot!.querySelector('slot[name="title"]') as HTMLSlotElement
194
- assert.ok(slot, 'has the slot')
195
- })
196
-
197
- it('does not render padding around the title slot', async () => {
198
- const element = await basicFixture()
199
- const container = element.shadowRoot!.querySelector('.title') as HTMLElement
200
- assert.isFalse(container.classList.contains('with-title'), 'has no with-title class')
201
- })
202
-
203
- it('renders padding around the title slot with a title', async () => {
204
- const element = await titleFixture()
205
- const container = element.shadowRoot!.querySelector('.title') as HTMLElement
206
- assert.isTrue(container.classList.contains('with-title'), 'has the with-title class')
207
- })
208
- })
209
-
210
- describe('buttons', () => {
211
- it('renders the button slot', async () => {
212
- const element = await basicFixture()
213
- const slot = element.shadowRoot!.querySelector('slot[name="button"]') as HTMLSlotElement
214
- assert.ok(slot, 'has the slot')
215
- })
216
-
217
- it('does not render padding around the buttons slot', async () => {
218
- const element = await basicFixture()
219
- const container = element.shadowRoot!.querySelector('.buttons') as HTMLElement
220
- assert.isFalse(container.classList.contains('with-buttons'), 'has no with-buttons class')
221
- })
222
-
223
- it('renders the confirm button', async () => {
224
- const element = await basicFixture()
225
- element.confirmLabel = 'OK label'
226
- await element.updateComplete
227
- const container = element.shadowRoot!.querySelector('.buttons') as HTMLElement
228
- assert.isTrue(container.classList.contains('with-buttons'), 'has the with-buttons class')
229
- const button = element.shadowRoot!.querySelector('.internal-button') as UiButton
230
- assert.ok(button, 'has the button')
231
- assert.equal(button.value, 'confirm')
232
- assert.equal(button.textContent!.trim(), 'OK label')
233
- })
234
-
235
- it('renders the dismiss button', async () => {
236
- const element = await basicFixture()
237
- element.dismissLabel = 'Cancel label'
238
- await element.updateComplete
239
- const container = element.shadowRoot!.querySelector('.buttons') as HTMLElement
240
- assert.isTrue(container.classList.contains('with-buttons'), 'has the with-buttons class')
241
- const button = element.shadowRoot!.querySelector('.internal-button') as UiButton
242
- assert.ok(button, 'has the button')
243
- assert.equal(button.value, 'dismiss')
244
- assert.equal(button.textContent!.trim(), 'Cancel label')
245
- })
246
-
247
- it('renders the slotted buttons', async () => {
248
- const element = await buttonFixture()
249
- const container = element.shadowRoot!.querySelector('.buttons') as HTMLElement
250
- assert.isTrue(container.classList.contains('with-buttons'), 'has the with-buttons class')
251
- })
252
-
253
- it('applies destructive class to confirm button when destructive is true', async () => {
254
- const element = await basicFixture()
255
- element.confirmLabel = 'Delete'
256
- element.destructive = true
257
- await element.updateComplete
258
-
259
- const button = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
260
- assert.ok(button, 'has the confirm button')
261
- assert.isTrue(button.classList.contains('destructive'), 'has destructive class')
262
- })
263
-
264
- it('does not apply destructive class when destructive is false', async () => {
265
- const element = await basicFixture()
266
- element.confirmLabel = 'Confirm'
267
- element.destructive = false
268
- await element.updateComplete
269
-
270
- const button = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
271
- assert.ok(button, 'has the confirm button')
272
- assert.isFalse(button.classList.contains('destructive'), 'does not have destructive class')
273
- })
274
- })
275
-
276
- describe('form handling', () => {
277
- async function formWrappedDialogFixture(): Promise<{ form: HTMLFormElement; dialog: UiDialog }> {
278
- const container = await fixture(html`
279
- <form>
280
- <ui-dialog submitClose>
281
- <span slot="title">Form Dialog</span>
282
- <input type="text" name="username" required />
283
- <ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
284
- <ui-button color="text" slot="button" value="confirm" type="submit">Submit</ui-button>
285
- </ui-dialog>
286
- </form>
287
- `)
288
- const form = container as HTMLFormElement
289
- const dialog = form.querySelector('ui-dialog') as UiDialog
290
- return { form, dialog }
291
- }
292
-
293
- async function formWithoutSubmitCloseFixture(): Promise<{ form: HTMLFormElement; dialog: UiDialog }> {
294
- const container = await fixture(html`
295
- <form>
296
- <ui-dialog>
297
- <span slot="title">Form Dialog</span>
298
- <input type="text" name="username" required />
299
- <ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
300
- <ui-button color="text" slot="button" value="confirm" type="submit">Submit</ui-button>
301
- </ui-dialog>
302
- </form>
303
- `)
304
- const form = container as HTMLFormElement
305
- const dialog = form.querySelector('ui-dialog') as UiDialog
306
- return { form, dialog }
307
- }
308
-
309
- describe('dialog wrapped in form', () => {
310
- it('should detect parent form when connected', async () => {
311
- const { dialog } = await formWrappedDialogFixture()
312
- await dialog.updateComplete
313
-
314
- // The form should be detected during connectedCallback
315
- // We can't directly access private fields, so we test the behavior instead
316
- assert.ok(dialog.submitClose, 'dialog should be configured for form handling')
317
- })
318
-
319
- it('should close dialog when form is submitted and submitClose is true', async () => {
320
- const { form, dialog } = await formWrappedDialogFixture()
321
- dialog.open = true
322
- await dialog.updateComplete
323
-
324
- const spy = sinon.spy()
325
- dialog.addEventListener('close', spy)
326
-
327
- // Simulate form submission
328
- const submitEvent = new SubmitEvent('submit', { bubbles: true, cancelable: true })
329
- form.dispatchEvent(submitEvent)
330
-
331
- assert.isFalse(dialog.open, 'dialog should be closed')
332
- assert.isTrue(spy.calledOnce, 'close event should be dispatched')
333
- const event = spy.args[0][0] as CustomEvent
334
- assert.isFalse(event.detail.cancelled, 'dialog should be confirmed, not cancelled')
335
- })
336
-
337
- it('should not close dialog when form is submitted and submitClose is false', async () => {
338
- const { form, dialog } = await formWithoutSubmitCloseFixture()
339
- dialog.open = true
340
- await dialog.updateComplete
341
-
342
- const spy = sinon.spy()
343
- dialog.addEventListener('close', spy)
344
-
345
- // Simulate form submission
346
- const submitEvent = new SubmitEvent('submit', { bubbles: true, cancelable: true })
347
- form.dispatchEvent(submitEvent)
348
-
349
- assert.isTrue(dialog.open, 'dialog should remain open')
350
- assert.isFalse(spy.called, 'close event should not be dispatched')
351
- })
352
-
353
- it('should not handle form submit when submit button is clicked directly', async () => {
354
- const { dialog } = await formWrappedDialogFixture()
355
- dialog.open = true
356
- await dialog.updateComplete
357
-
358
- const submitButton = dialog.querySelector('ui-button[type="submit"]') as UiButton
359
- const spy = sinon.spy()
360
- dialog.addEventListener('close', spy)
361
-
362
- // Click the submit button - this should not close the dialog immediately
363
- // because we yield control to the form
364
- submitButton.click()
365
-
366
- // The dialog should still be open because the form hasn't been submitted yet
367
- assert.isTrue(dialog.open, 'dialog should remain open when submit button is clicked')
368
- })
369
-
370
- it('should remove form event listener when disconnected', async () => {
371
- const { form, dialog } = await formWrappedDialogFixture()
372
- const removeEventListenerSpy = sinon.spy(form, 'removeEventListener')
373
-
374
- dialog.remove()
375
-
376
- // We can't test the private method directly, but we can verify the spy was called
377
- // The actual method name is not accessible, so we test the behavior instead
378
- assert.isTrue(removeEventListenerSpy.called, 'removeEventListener should be called on form')
379
- })
380
- })
381
-
382
- describe('edge cases', () => {
383
- it('should handle form submission when dialog is not open', async () => {
384
- const { form, dialog } = await formWrappedDialogFixture()
385
- // Dialog is closed by default
386
- assert.isFalse(dialog.open, 'dialog should be closed initially')
387
-
388
- const spy = sinon.spy()
389
- dialog.addEventListener('close', spy)
390
-
391
- // Submit form when dialog is closed
392
- const submitEvent = new SubmitEvent('submit', { bubbles: true, cancelable: true })
393
- form.dispatchEvent(submitEvent)
394
-
395
- // Should still close the dialog (set open to false even though it's already false)
396
- assert.isFalse(dialog.open, 'dialog should remain closed')
397
- assert.isTrue(spy.calledOnce, 'close event should still be dispatched')
398
- })
399
-
400
- it('should handle multiple form submissions', async () => {
401
- const { form, dialog } = await formWrappedDialogFixture()
402
- dialog.open = true
403
- await dialog.updateComplete
404
-
405
- const spy = sinon.spy()
406
- dialog.addEventListener('close', spy)
407
-
408
- // Submit form multiple times
409
- const submitEvent1 = new SubmitEvent('submit', { bubbles: true, cancelable: true })
410
- const submitEvent2 = new SubmitEvent('submit', { bubbles: true, cancelable: true })
411
-
412
- form.dispatchEvent(submitEvent1)
413
- form.dispatchEvent(submitEvent2)
414
-
415
- assert.equal(spy.callCount, 2, 'close event should be dispatched for each submission')
416
- })
417
-
418
- it('should maintain form reference across re-connections', async () => {
419
- const { form, dialog } = await formWrappedDialogFixture()
420
-
421
- // Remove and re-add dialog
422
- const parent = form
423
- dialog.remove()
424
- await dialog.updateComplete
425
-
426
- parent.appendChild(dialog)
427
- await dialog.updateComplete
428
-
429
- // Test the behavior instead of accessing private fields
430
- // If form handling is working, submitClose should still work
431
- dialog.open = true
432
- await dialog.updateComplete
433
-
434
- const spy = sinon.spy()
435
- dialog.addEventListener('close', spy)
436
-
437
- const submitEvent = new SubmitEvent('submit', { bubbles: true, cancelable: true })
438
- form.dispatchEvent(submitEvent)
439
-
440
- assert.isTrue(spy.called, 'form handling should work after reconnection')
441
- })
442
- })
443
- })
444
-
445
- describe('closing event', () => {
446
- it('dispatches the closing event before close event when dismissing', async () => {
447
- const element = await buttonFixture()
448
- const closingSpy = sinon.spy()
449
- const closeSpy = sinon.spy()
450
- element.addEventListener('closing', closingSpy)
451
- element.addEventListener('close', closeSpy)
452
-
453
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
454
- button.click()
455
-
456
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
457
- assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
458
- assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
459
- })
460
-
461
- it('dispatches the closing event before close event when confirming', async () => {
462
- const element = await buttonFixture()
463
- const closingSpy = sinon.spy()
464
- const closeSpy = sinon.spy()
465
- element.addEventListener('closing', closingSpy)
466
- element.addEventListener('close', closeSpy)
467
-
468
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
469
- button.click()
470
-
471
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
472
- assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
473
- assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
474
- })
475
-
476
- it('dispatches the closing event when pressing Escape', async () => {
477
- const element = await buttonFixture()
478
- const closingSpy = sinon.spy()
479
- const closeSpy = sinon.spy()
480
- element.addEventListener('closing', closingSpy)
481
- element.addEventListener('close', closeSpy)
482
-
483
- element.open = true
484
- await element.updateComplete
485
- const button = element.querySelector('ui-button')!
486
- button.focus()
487
- await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
488
-
489
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
490
- assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
491
- assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
492
- })
493
-
494
- it('dispatches the closing event with correct detail for dismiss action', async () => {
495
- const element = await buttonFixture()
496
- const closingSpy = sinon.spy()
497
- element.addEventListener('closing', closingSpy)
498
-
499
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
500
- button.click()
501
-
502
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
503
- const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
504
- assert.isTrue(event.detail.cancelled, 'cancelled flag is true for dismiss action')
505
- assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
506
- })
507
-
508
- it('dispatches the closing event with correct detail for confirm action', async () => {
509
- const element = await buttonFixture()
510
- const closingSpy = sinon.spy()
511
- element.addEventListener('closing', closingSpy)
512
-
513
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
514
- button.click()
515
-
516
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
517
- const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
518
- assert.isFalse(event.detail.cancelled, 'cancelled flag is false for confirm action')
519
- assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
520
- })
521
-
522
- it('includes dialogValue in closing event detail', async () => {
523
- const element = await buttonFixture()
524
- element.dialogValue = 'test-value'
525
- const closingSpy = sinon.spy()
526
- element.addEventListener('closing', closingSpy)
527
-
528
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
529
- button.click()
530
-
531
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
532
- const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
533
- assert.equal(event.detail.value, 'test-value', 'dialogValue is included in event detail')
534
- })
535
-
536
- it('prevents dialog closing when closing event is cancelled', async () => {
537
- const element = await buttonFixture()
538
- const closingSpy = sinon.spy()
539
- const closeSpy = sinon.spy()
540
-
541
- element.addEventListener('closing', (event) => {
542
- closingSpy()
543
- event.preventDefault() // Cancel the closing
544
- })
545
- element.addEventListener('close', closeSpy)
546
-
547
- element.open = true
548
- await element.updateComplete
549
- assert.isTrue(element.open, 'dialog is initially open')
550
-
551
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
552
- button.click()
553
-
554
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
555
- assert.isFalse(closeSpy.called, 'close event was not dispatched')
556
- assert.isTrue(element.open, 'dialog remains open when closing is prevented')
557
- })
558
-
559
- it('prevents dialog closing when confirming and closing event is cancelled', async () => {
560
- const element = await buttonFixture()
561
- const closingSpy = sinon.spy()
562
- const closeSpy = sinon.spy()
563
-
564
- element.addEventListener('closing', (event) => {
565
- closingSpy()
566
- event.preventDefault() // Cancel the closing
567
- })
568
- element.addEventListener('close', closeSpy)
569
-
570
- element.open = true
571
- await element.updateComplete
572
- assert.isTrue(element.open, 'dialog is initially open')
573
-
574
- const button = element.querySelector('ui-button[value="confirm"]') as UiButton
575
- button.click()
576
-
577
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
578
- assert.isFalse(closeSpy.called, 'close event was not dispatched')
579
- assert.isTrue(element.open, 'dialog remains open when closing is prevented')
580
- })
581
-
582
- it('prevents dialog closing when pressing Escape and closing event is cancelled', async () => {
583
- const element = await buttonFixture()
584
- const closingSpy = sinon.spy()
585
- const closeSpy = sinon.spy()
586
-
587
- element.addEventListener('closing', (event) => {
588
- closingSpy()
589
- event.preventDefault() // Cancel the closing
590
- })
591
- element.addEventListener('close', closeSpy)
592
-
593
- element.open = true
594
- await element.updateComplete
595
- assert.isTrue(element.open, 'dialog is initially open')
596
-
597
- const button = element.querySelector('ui-button')!
598
- button.focus()
599
- await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
600
-
601
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
602
- assert.isFalse(closeSpy.called, 'close event was not dispatched')
603
- assert.isTrue(element.open, 'dialog remains open when closing is prevented')
604
- })
605
-
606
- it('prevents native dialog close and reopens when closing event is cancelled', async () => {
607
- const element = await modalFixture()
608
- const closingSpy = sinon.spy()
609
- const showModalSpy = sinon.spy(element.dialog, 'showModal')
610
-
611
- element.addEventListener('closing', (event) => {
612
- closingSpy()
613
- event.preventDefault() // Cancel the closing
614
- })
615
-
616
- element.open = true
617
- await element.updateComplete
618
- assert.isTrue(element.open, 'dialog is initially open')
619
- assert.isTrue(element.dialog.open, 'native dialog is open')
620
-
621
- // Reset the spy count after initial open
622
- showModalSpy.resetHistory()
623
-
624
- // Simulate native dialog close event (e.g., clicking backdrop)
625
- element.dialog.dispatchEvent(new Event('close'))
626
-
627
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
628
- assert.isTrue(element.open, 'dialog remains open when closing is prevented')
629
- assert.isTrue(showModalSpy.calledOnce, 'showModal was called to reopen the dialog')
630
- })
631
-
632
- it('verifies closing event properties', async () => {
633
- const element = await buttonFixture()
634
- let closingEvent: CustomEvent<UiDialogClosingReason>
635
-
636
- element.addEventListener('closing', (event) => {
637
- closingEvent = event as CustomEvent<UiDialogClosingReason>
638
- })
639
-
640
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
641
- button.click()
642
-
643
- assert.isDefined(closingEvent!, 'closing event was dispatched')
644
- assert.isTrue(closingEvent!.cancelable, 'closing event is cancelable')
645
- assert.isFalse(closingEvent!.bubbles, 'closing event does not bubble')
646
- assert.isFalse(closingEvent!.composed, 'closing event is not composed')
647
- assert.equal(closingEvent!.type, 'closing', 'event type is "closing"')
648
- })
649
-
650
- it('works with imperative dismiss and confirm buttons', async () => {
651
- const element = await basicFixture()
652
- element.dismissLabel = 'Cancel'
653
- element.confirmLabel = 'OK'
654
- await element.updateComplete
655
-
656
- const closingSpy = sinon.spy()
657
- const closeSpy = sinon.spy()
658
- element.addEventListener('closing', closingSpy)
659
- element.addEventListener('close', closeSpy)
660
-
661
- // Test dismiss button
662
- const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
663
- dismissButton.click()
664
-
665
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for dismiss')
666
- assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for dismiss')
667
-
668
- // Reset spies and test confirm button
669
- closingSpy.resetHistory()
670
- closeSpy.resetHistory()
671
- element.open = true
672
- await element.updateComplete
673
-
674
- const confirmButton = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
675
- confirmButton.click()
676
-
677
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for confirm')
678
- assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for confirm')
679
- })
680
-
681
- it('can prevent closing with imperative buttons', async () => {
682
- const element = await basicFixture()
683
- element.dismissLabel = 'Cancel'
684
- await element.updateComplete
685
-
686
- const closingSpy = sinon.spy()
687
- const closeSpy = sinon.spy()
688
-
689
- element.addEventListener('closing', (event) => {
690
- closingSpy()
691
- event.preventDefault()
692
- })
693
- element.addEventListener('close', closeSpy)
694
-
695
- element.open = true
696
- await element.updateComplete
697
-
698
- const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
699
- dismissButton.click()
700
-
701
- assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
702
- assert.isFalse(closeSpy.called, 'close event was not dispatched')
703
- assert.isTrue(element.open, 'dialog remains open')
704
- })
705
- })
706
-
707
- describe('accessibility', () => {
708
- it('meets accessibility standards in closed state', async () => {
709
- const element = await basicFixture()
710
- await assert.isAccessible(element)
711
- })
712
-
713
- it('meets accessibility standards when open', async () => {
714
- const element = await basicFixture()
715
- element.open = true
716
- await element.updateComplete
717
- await assert.isAccessible(element)
718
- })
719
-
720
- it('meets accessibility standards with modal dialog', async () => {
721
- const element = await modalFixture()
722
- element.open = true
723
- await element.updateComplete
724
- await assert.isAccessible(element)
725
- })
726
-
727
- it('meets accessibility standards with full content', async () => {
728
- const element: UiDialog = await fixture(html`
729
- <ui-dialog modal open>
730
- <ui-icon slot="icon" icon="deleteOutline"></ui-icon>
731
- <span slot="title">Delete confirmation</span>
732
- <p>Are you sure you want to delete this item?</p>
733
- <ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
734
- <ui-button color="text" slot="button" value="confirm">Delete</ui-button>
735
- </ui-dialog>
736
- `)
737
- await element.updateComplete
738
- await assert.isAccessible(element)
739
- })
740
-
741
- it('maintains accessibility when closing is prevented', async () => {
742
- const element = await buttonFixture()
743
- element.addEventListener('closing', (event) => {
744
- event.preventDefault()
745
- })
746
-
747
- element.open = true
748
- await element.updateComplete
749
-
750
- const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
751
- button.click()
752
-
753
- // Dialog should remain open and accessible
754
- assert.isTrue(element.open, 'dialog remains open')
755
- await assert.isAccessible(element)
756
- })
757
- })
758
- })
759
- })