@kubex/zinc 1.1.185 → 2.0.0

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 (358) hide show
  1. package/.browserslistrc +2 -0
  2. package/.github/workflows/js_build_and_deploy.yaml +54 -1
  3. package/.github/workflows/test.yaml +27 -0
  4. package/dist/chunks/zn.UWJLIXDT.js +1 -0
  5. package/dist/custom-elements.json +9998 -2345
  6. package/dist/vscode.html-custom-data.json +1022 -67
  7. package/dist/web-types.json +2129 -177
  8. package/dist/zn.d.ts +2293 -416
  9. package/dist/zn.min.css +1 -1
  10. package/dist/zn.min.js +2310 -1637
  11. package/docs/_includes/default.njk +4 -1
  12. package/docs/assets/scripts/docs.js +22 -6
  13. package/docs/assets/styles/docs.css +9 -2
  14. package/docs/data/report-table-day-compare.json +380 -0
  15. package/docs/data/report-table.json +314 -0
  16. package/docs/pages/components/avatar-group.md +57 -0
  17. package/docs/pages/components/badge.md +67 -0
  18. package/docs/pages/components/button.md +41 -1
  19. package/docs/pages/components/chat-message.md +16 -0
  20. package/docs/pages/components/checkbox.md +1 -1
  21. package/docs/pages/components/chip.md +25 -13
  22. package/docs/pages/components/color-picker.md +37 -0
  23. package/docs/pages/components/copy-button.md +2 -2
  24. package/docs/pages/components/data-table-filter.md +33 -50
  25. package/docs/pages/components/data-table-search.md +4 -4
  26. package/docs/pages/components/data-table.md +27 -3
  27. package/docs/pages/components/date-range.md +116 -0
  28. package/docs/pages/components/dialog.md +29 -37
  29. package/docs/pages/components/diff-row.md +28 -0
  30. package/docs/pages/components/diff.md +46 -0
  31. package/docs/pages/components/editor.md +55 -0
  32. package/docs/pages/components/icon.md +46 -1
  33. package/docs/pages/components/input.md +30 -11
  34. package/docs/pages/components/item.md +35 -0
  35. package/docs/pages/components/key-value.md +25 -0
  36. package/docs/pages/components/menu.md +74 -7
  37. package/docs/pages/components/nav-item.md +15 -0
  38. package/docs/pages/components/nav-list.md +132 -0
  39. package/docs/pages/components/navbar.md +100 -1
  40. package/docs/pages/components/page.md +242 -74
  41. package/docs/pages/components/priority-list.md +43 -5
  42. package/docs/pages/components/query-builder.md +23 -0
  43. package/docs/pages/components/radio-group.md +33 -1
  44. package/docs/pages/components/radio.md +1 -1
  45. package/docs/pages/components/report-table.md +202 -0
  46. package/docs/pages/components/stat.md +30 -0
  47. package/docs/pages/components/tile.md +11 -0
  48. package/docs/pages/components/tooltip.md +1 -1
  49. package/docs/pages/components/translation-grid.md +86 -0
  50. package/docs/pages/components/vertical-stepper.md +108 -64
  51. package/package.json +2 -1
  52. package/scss/_global-spacing.scss +2 -2
  53. package/scss/_root.scss +11 -171
  54. package/scss/boot.scss +14 -0
  55. package/scss/mixins/_helper-mixins.scss +24 -2
  56. package/scss/mixins/_motion-mixins.scss +126 -0
  57. package/scss/mixins/_spacing-mixins.scss +4 -3
  58. package/scss/mixins/_tab-indicator-mixins.scss +12 -0
  59. package/scss/mixins/_typography-mixins.scss +1 -1
  60. package/scss/mixins/index.scss +14 -0
  61. package/scss/shared/_base.scss +32 -1
  62. package/scss/shared/_button-mixin.scss +7 -5
  63. package/scss/shared/_table.scss +35 -4
  64. package/scss/shared/nav.scss +4 -0
  65. package/scss/shared/shimmer.scss +1 -1
  66. package/scss/table-controls.scss +206 -0
  67. package/scss/themes/_dark.scss +1 -3
  68. package/scss/themes/_index.scss +1 -1
  69. package/scss/themes/_light.scss +46 -6
  70. package/scss/themes/_modes.scss +11 -11
  71. package/scss/themes/_openbyte.scss +944 -0
  72. package/scss/themes/_typography.scss +4 -2
  73. package/scss/variables/index.scss +0 -9
  74. package/src/components/alert/alert.component.ts +14 -4
  75. package/src/components/alert/alert.scss +55 -69
  76. package/src/components/alert/alert.test.ts +8 -0
  77. package/src/components/animated-button/animated-button.component.ts +3 -2
  78. package/src/components/animated-button/animated-button.scss +6 -23
  79. package/src/components/animated-button/animated-button.test.ts +4 -3
  80. package/src/components/avatar-group/avatar-group.component.ts +84 -0
  81. package/src/components/avatar-group/avatar-group.scss +54 -0
  82. package/src/components/avatar-group/avatar-group.test.ts +59 -0
  83. package/src/components/avatar-group/index.ts +12 -0
  84. package/src/components/badge/badge.component.ts +49 -0
  85. package/src/components/badge/badge.scss +80 -0
  86. package/src/components/badge/badge.test.ts +34 -0
  87. package/src/components/badge/index.ts +12 -0
  88. package/src/components/bulk-actions/bulk-actions.component.ts +14 -2
  89. package/src/components/button/button.component.ts +228 -8
  90. package/src/components/button/button.scss +115 -32
  91. package/src/components/button/button.test.ts +122 -0
  92. package/src/components/button-menu/button-menu.component.ts +32 -11
  93. package/src/components/button-menu/button-menu.scss +5 -1
  94. package/src/components/channel-tile/channel-tile.component.ts +34 -27
  95. package/src/components/channel-tile/channel-tile.scss +76 -43
  96. package/src/components/chart/builders.test.ts +46 -0
  97. package/src/components/chart/builders.ts +27 -3
  98. package/src/components/chart/chart-live.test.ts +4 -6
  99. package/src/components/chart/chart.component.ts +125 -5
  100. package/src/components/chart/chart.scss +121 -0
  101. package/src/components/chart/chart.test.ts +81 -0
  102. package/src/components/chat-message/chat-message.component.ts +21 -1
  103. package/src/components/chat-message/chat-message.scss +13 -2
  104. package/src/components/chat-message/chat-message.test.ts +9 -0
  105. package/src/components/checkbox/checkbox.component.ts +61 -27
  106. package/src/components/checkbox/checkbox.scss +58 -25
  107. package/src/components/checkbox-group/checkbox-group.component.ts +7 -1
  108. package/src/components/chip/chip.component.ts +11 -1
  109. package/src/components/chip/chip.scss +91 -26
  110. package/src/components/chip/chip.test.ts +17 -0
  111. package/src/components/collapsible/collapsible.component.ts +17 -3
  112. package/src/components/collapsible/collapsible.scss +19 -10
  113. package/src/components/color-picker/color-picker.component.ts +277 -0
  114. package/src/components/color-picker/color-picker.scss +141 -0
  115. package/src/components/color-picker/color-picker.test.ts +57 -0
  116. package/src/components/color-picker/index.ts +12 -0
  117. package/src/components/cols/cols.component.ts +10 -0
  118. package/src/components/cols/cols.test.ts +17 -0
  119. package/src/components/confirm/confirm.component.ts +20 -6
  120. package/src/components/confirm/confirm.test.ts +52 -0
  121. package/src/components/content-block/content-block.component.ts +38 -9
  122. package/src/components/content-block/content-block.scss +11 -5
  123. package/src/components/content-block/content-block.test.ts +26 -0
  124. package/src/components/copy-button/copy-button.component.ts +2 -2
  125. package/src/components/copy-button/copy-button.scss +17 -4
  126. package/src/components/data-select/data-select.component.ts +3 -1
  127. package/src/components/data-table/data-table.component.ts +362 -140
  128. package/src/components/data-table/data-table.scss +133 -60
  129. package/src/components/data-table/data-table.test.ts +356 -4
  130. package/src/components/data-table-filter/data-table-filter.component.ts +426 -406
  131. package/src/components/data-table-filter/data-table-filter.scss +176 -148
  132. package/src/components/data-table-filter/data-table-filter.test.ts +271 -273
  133. package/src/components/data-table-search/data-table-search.component.ts +4 -2
  134. package/src/components/data-table-search/data-table-search.scss +8 -1
  135. package/src/components/data-table-search/data-table-search.test.ts +29 -0
  136. package/src/components/date-range/date-range-math.test.ts +78 -0
  137. package/src/components/date-range/date-range-math.ts +105 -0
  138. package/src/components/date-range/date-range.component.ts +375 -0
  139. package/src/components/date-range/date-range.scss +272 -0
  140. package/src/components/date-range/date-range.test.ts +247 -0
  141. package/src/components/date-range/index.ts +12 -0
  142. package/src/components/datepicker/datepicker.component.ts +44 -7
  143. package/src/components/datepicker/datepicker.scss +9 -0
  144. package/src/components/datepicker/datepicker.test.ts +2 -2
  145. package/src/components/dialog/dialog.component.ts +38 -19
  146. package/src/components/dialog/dialog.scss +65 -36
  147. package/src/components/dialog/dialog.test.ts +14 -0
  148. package/src/components/diff/diff.component.ts +55 -0
  149. package/src/components/diff/diff.scss +46 -0
  150. package/src/components/diff/diff.test.ts +15 -0
  151. package/src/components/diff/index.ts +12 -0
  152. package/src/components/diff-row/diff-row.component.ts +75 -0
  153. package/src/components/diff-row/diff-row.scss +70 -0
  154. package/src/components/diff-row/diff-row.test.ts +37 -0
  155. package/src/components/diff-row/index.ts +12 -0
  156. package/src/components/dropdown/dropdown.component.ts +12 -10
  157. package/src/components/dropdown/dropdown.scss +2 -0
  158. package/src/components/editor/editor.component.ts +159 -11
  159. package/src/components/editor/editor.scss +250 -1
  160. package/src/components/editor/editor.test.ts +31 -3
  161. package/src/components/editor/modules/ai/panel/ai-panel.scss +0 -1
  162. package/src/components/editor/modules/attachment/attachment.ts +53 -31
  163. package/src/components/editor/modules/context-menu/context-menu.ts +17 -0
  164. package/src/components/editor/modules/dialog/dialog.component.ts +23 -1
  165. package/src/components/editor/modules/dialog/dialog.test.ts +28 -0
  166. package/src/components/editor/modules/emoji/emoji.ts +4 -5
  167. package/src/components/editor/modules/merge-field/merge-field.ts +83 -0
  168. package/src/components/editor/modules/toolbar/toolbar.component.ts +121 -68
  169. package/src/components/editor/modules/toolbar/toolbar.scss +38 -0
  170. package/src/components/editor/modules/toolbar/toolbar.ts +25 -1
  171. package/src/components/empty-state/empty-state.component.ts +6 -1
  172. package/src/components/empty-state/empty-state.scss +21 -4
  173. package/src/components/expanding-action/expanding-action.component.ts +22 -34
  174. package/src/components/expanding-action/expanding-action.scss +3 -45
  175. package/src/components/expanding-action/expanding-action.test.ts +2 -1
  176. package/src/components/file/file.component.ts +30 -2
  177. package/src/components/file/file.scss +6 -0
  178. package/src/components/flow-builder/flow-builder.component.ts +36 -3
  179. package/src/components/flow-builder/flow-builder.scss +0 -6
  180. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +8 -0
  181. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +10 -5
  182. package/src/components/flow-builder/modules/flow-node/flow-node.component.ts +17 -0
  183. package/src/components/flow-builder/modules/flow-node/flow-node.scss +10 -0
  184. package/src/components/form-actions/form-actions.component.ts +48 -2
  185. package/src/components/form-actions/form-actions.scss +1 -1
  186. package/src/components/form-group/form-group.component.ts +10 -3
  187. package/src/components/form-group/form-group.scss +37 -4
  188. package/src/components/form-group/form-group.test.ts +10 -0
  189. package/src/components/header/header.component.ts +11 -4
  190. package/src/components/header/header.scss +47 -5
  191. package/src/components/hover-container/hover-container.component.ts +4 -5
  192. package/src/components/icon/icon.component.ts +95 -9
  193. package/src/components/icon/icon.scss +70 -6
  194. package/src/components/icon/icon.test.ts +55 -0
  195. package/src/components/icon-picker/icon-picker.component.ts +35 -1
  196. package/src/components/inline-edit/inline-edit.component.ts +38 -8
  197. package/src/components/inline-edit/inline-edit.scss +128 -19
  198. package/src/components/input/input.component.ts +173 -297
  199. package/src/components/input/input.scss +65 -43
  200. package/src/components/input/input.test.ts +86 -4
  201. package/src/components/item/item.component.ts +12 -0
  202. package/src/components/item/item.scss +102 -3
  203. package/src/components/item/item.test.ts +23 -0
  204. package/src/components/key/key.component.ts +2 -2
  205. package/src/components/key/key.scss +11 -0
  206. package/src/components/key-value/index.ts +12 -0
  207. package/src/components/key-value/key-value.component.ts +160 -0
  208. package/src/components/key-value/key-value.scss +20 -0
  209. package/src/components/key-value/key-value.test.ts +22 -0
  210. package/src/components/markdown-editor/markdown-editor.component.ts +8 -1
  211. package/src/components/menu/menu.component.ts +21 -2
  212. package/src/components/menu/menu.scss +43 -23
  213. package/src/components/menu/menu.test.ts +33 -0
  214. package/src/components/menu-item/menu-item.component.ts +13 -2
  215. package/src/components/menu-item/menu-item.scss +56 -23
  216. package/src/components/menu-item/menu-item.test.ts +31 -0
  217. package/src/components/menu-item/submenu-controller.ts +25 -15
  218. package/src/components/menu-label/index.ts +12 -0
  219. package/src/components/menu-label/menu-label.component.ts +30 -0
  220. package/src/components/menu-label/menu-label.scss +18 -0
  221. package/src/components/nav-item/index.ts +12 -0
  222. package/src/components/nav-item/nav-item.component.ts +83 -0
  223. package/src/components/nav-item/nav-item.scss +128 -0
  224. package/src/components/nav-list/index.ts +12 -0
  225. package/src/components/nav-list/nav-list.component.ts +313 -0
  226. package/src/components/nav-list/nav-list.scss +87 -0
  227. package/src/components/nav-list/nav-list.test.ts +250 -0
  228. package/src/components/navbar/navbar.component.ts +235 -171
  229. package/src/components/navbar/navbar.scss +333 -169
  230. package/src/components/navbar/navbar.test.ts +63 -143
  231. package/src/components/page/page.component.ts +114 -29
  232. package/src/components/page/page.scss +223 -95
  233. package/src/components/page/page.test.ts +214 -3
  234. package/src/components/page-builder/page-builder.component.ts +51 -5
  235. package/src/components/page-builder/page-builder.scss +6 -1
  236. package/src/components/page-nav/page-nav.component.ts +25 -3
  237. package/src/components/page-nav/page-nav.scss +10 -2
  238. package/src/components/pagination/pagination.scss +1 -1
  239. package/src/components/panel/panel.component.ts +14 -13
  240. package/src/components/panel/panel.scss +14 -10
  241. package/src/components/panel/panel.test.ts +42 -0
  242. package/src/components/popup/popup.component.ts +20 -13
  243. package/src/components/popup/popup.test.ts +21 -1
  244. package/src/components/priority-list/priority-list.component.ts +157 -172
  245. package/src/components/priority-list/priority-list.scss +113 -17
  246. package/src/components/priority-list/priority-list.test.ts +301 -3
  247. package/src/components/progress-bar/progress-bar.component.ts +1 -1
  248. package/src/components/progress-bar/progress-bar.scss +16 -4
  249. package/src/components/progress-tile/progress-tile.scss +1 -1
  250. package/src/components/query-builder/query-builder.component.ts +85 -10
  251. package/src/components/query-builder/query-builder.scss +7 -1
  252. package/src/components/query-builder/query-builder.test.ts +40 -0
  253. package/src/components/radio/radio.component.ts +57 -18
  254. package/src/components/radio/radio.scss +101 -26
  255. package/src/components/radio-group/radio-group.component.ts +45 -7
  256. package/src/components/radio-group/radio-group.scss +17 -0
  257. package/src/components/radio-group/radio-group.test.ts +63 -2
  258. package/src/components/rating/rating.component.ts +23 -0
  259. package/src/components/rating/rating.scss +1 -1
  260. package/src/components/remarkd-editor/remarkd-editor.component.ts +60 -5
  261. package/src/components/remarkd-editor/remarkd-editor.scss +12 -4
  262. package/src/components/report-table/index.ts +12 -0
  263. package/src/components/report-table/report-format.test.ts +86 -0
  264. package/src/components/report-table/report-format.ts +72 -0
  265. package/src/components/report-table/report-math.test.ts +74 -0
  266. package/src/components/report-table/report-math.ts +252 -0
  267. package/src/components/report-table/report-table.component.ts +681 -0
  268. package/src/components/report-table/report-table.scss +328 -0
  269. package/src/components/report-table/report-table.test.ts +702 -0
  270. package/src/components/reveal/reveal.component.ts +15 -1
  271. package/src/components/reveal/reveal.scss +5 -0
  272. package/src/components/schedule-builder/schedule-builder.component.ts +23 -8
  273. package/src/components/scroll-container/scroll-container.component.ts +19 -1
  274. package/src/components/scroll-container/scroll-container.scss +6 -1
  275. package/src/components/select/select.component.ts +52 -36
  276. package/src/components/select/select.scss +42 -25
  277. package/src/components/select/select.test.ts +14 -2
  278. package/src/components/settings-container/settings-container.scss +18 -5
  279. package/src/components/sidebar/sidebar.component.ts +8 -1
  280. package/src/components/sidebar/sidebar.scss +6 -1
  281. package/src/components/skeleton/skeleton.component.ts +3 -3
  282. package/src/components/skeleton/skeleton.scss +6 -6
  283. package/src/components/skeleton/skeleton.test.ts +9 -0
  284. package/src/components/slash-menu/slash-menu.scss +1 -1
  285. package/src/components/slideout/slideout.component.ts +20 -3
  286. package/src/components/slideout/slideout.scss +13 -6
  287. package/src/components/slideout/slideout.test.ts +19 -0
  288. package/src/components/split-button/split-button.component.ts +1 -1
  289. package/src/components/split-pane/split-pane.component.ts +71 -8
  290. package/src/components/split-pane/split-pane.scss +145 -41
  291. package/src/components/split-pane/split-pane.test.ts +23 -3
  292. package/src/components/stat/stat.component.ts +209 -14
  293. package/src/components/stat/stat.scss +305 -5
  294. package/src/components/stat/stat.test.ts +143 -2
  295. package/src/components/status-indicator/status-indicator.scss +22 -21
  296. package/src/components/stepper/stepper.scss +3 -3
  297. package/src/components/tab/tab.component.ts +1 -0
  298. package/src/components/table/table.component.ts +12 -1
  299. package/src/components/table/table.scss +21 -13
  300. package/src/components/table/table.test.ts +17 -0
  301. package/src/components/tabs/tabs.component.ts +150 -37
  302. package/src/components/tabs/tabs.scss +48 -7
  303. package/src/components/tabs/tabs.test.ts +169 -0
  304. package/src/components/textarea/textarea.component.ts +25 -3
  305. package/src/components/textarea/textarea.scss +10 -0
  306. package/src/components/textarea/textarea.test.ts +8 -4
  307. package/src/components/theme-editor/theme-editor.scss +0 -6
  308. package/src/components/tile/tile.component.ts +32 -2
  309. package/src/components/tile/tile.scss +40 -7
  310. package/src/components/tile/tile.test.ts +10 -0
  311. package/src/components/toggle/toggle.component.ts +23 -7
  312. package/src/components/toggle/toggle.scss +36 -29
  313. package/src/components/toggle/toggle.test.ts +17 -0
  314. package/src/components/tooltip/tooltip.component.ts +3 -0
  315. package/src/components/tooltip/tooltip.scss +11 -6
  316. package/src/components/tooltip/tooltip.test.ts +12 -0
  317. package/src/components/translation-field/index.ts +12 -0
  318. package/src/components/translation-field/translation-field.component.ts +55 -0
  319. package/src/components/translation-field/translation-field.scss +101 -0
  320. package/src/components/translation-fields/index.ts +12 -0
  321. package/src/components/translation-fields/translation-fields.component.ts +80 -0
  322. package/src/components/translation-fields/translation-fields.scss +60 -0
  323. package/src/components/translation-grid/index.ts +12 -0
  324. package/src/components/translation-grid/translation-grid.component.ts +157 -0
  325. package/src/components/translation-grid/translation-grid.scss +138 -0
  326. package/src/components/translation-grid/translation-grid.test.ts +28 -0
  327. package/src/components/vertical-stepper/vertical-stepper.component.ts +35 -9
  328. package/src/components/vertical-stepper/vertical-stepper.scss +110 -39
  329. package/src/components/vertical-stepper/vertical-stepper.test.ts +35 -0
  330. package/src/components/well/well.scss +2 -2
  331. package/src/events/events.ts +2 -0
  332. package/src/events/zn-chart-click.ts +13 -0
  333. package/src/events/zn-report-change.ts +7 -0
  334. package/src/form-control.scss +36 -3
  335. package/src/internal/anchored-popover.ts +175 -0
  336. package/src/internal/animate.ts +19 -5
  337. package/src/internal/cosmic-border.ts +15 -0
  338. package/src/internal/form.ts +1 -1
  339. package/src/internal/hover-intent.ts +15 -0
  340. package/src/internal/input-modality.ts +15 -0
  341. package/src/internal/pointer-intent.ts +37 -0
  342. package/src/internal/reorder.ts +625 -0
  343. package/src/internal/scroll.ts +51 -3
  344. package/src/internal/selection-card.ts +1 -1
  345. package/src/internal/tab-indicator.ts +92 -0
  346. package/src/internal/table-sort.ts +25 -0
  347. package/src/internal/table-tabs.ts +108 -0
  348. package/src/internal/test-drag.ts +35 -0
  349. package/src/internal/theme-openbyte.test.ts +126 -0
  350. package/src/internal/theme.ts +4 -4
  351. package/src/internal/zinc-element.ts +2 -2
  352. package/src/selection-card.scss +25 -0
  353. package/src/types/web-test-runner-commands.d.ts +1 -0
  354. package/src/utilities/color.test.ts +43 -0
  355. package/src/utilities/color.ts +189 -0
  356. package/src/zinc.ts +14 -0
  357. package/.github/workflows/eleventy_build.yml +0 -42
  358. package/scss/themes/_aura.scss +0 -114
@@ -1,8 +1,19 @@
1
1
  import '../../../dist/zn.min.js';
2
2
  import {expect, fixture, html, waitUntil} from '@open-wc/testing';
3
+ import type ZnConfirm from '../confirm/confirm.component';
3
4
  import type ZnDropdown from '../dropdown/dropdown.component';
5
+ import type ZnMenuItem from './menu-item.component';
4
6
 
5
7
  describe('<zn-menu-item>', () => {
8
+ it('should show its shortcut as a key cap only when set', async () => {
9
+ const el = await fixture<ZnMenuItem>(html`<zn-menu-item>Send email</zn-menu-item>`);
10
+ expect(el.shadowRoot!.querySelector('[part="shortcut"]')).to.be.null;
11
+
12
+ el.shortcut = 'E';
13
+ await el.updateComplete;
14
+ expect(el.shadowRoot!.querySelector('[part="shortcut"]')!.textContent).to.equal('E');
15
+ });
16
+
6
17
  it('should render a component', async () => {
7
18
  const el = await fixture(html` <zn-menu-item></zn-menu-item> `);
8
19
 
@@ -45,4 +56,24 @@ describe('<zn-menu-item>', () => {
45
56
  expect(dropdown.open).to.be.false;
46
57
  });
47
58
  });
59
+
60
+ it('closes its dropdown once the confirm dialog closes', async () => {
61
+ const dropdown = await fixture<ZnDropdown>(html`
62
+ <zn-dropdown>
63
+ <zn-button slot="trigger">Open</zn-button>
64
+ <zn-menu>
65
+ <zn-confirm trigger="delete-item" content="Delete?"></zn-confirm>
66
+ <zn-menu-item id="delete-item" confirm>Delete</zn-menu-item>
67
+ </zn-menu>
68
+ </zn-dropdown>`);
69
+ await dropdown.show();
70
+ const confirm = dropdown.querySelector<ZnConfirm>('zn-confirm')!;
71
+
72
+ dropdown.querySelector('zn-menu-item')!.click();
73
+ await dropdown.updateComplete;
74
+ expect(dropdown.open).to.be.true;
75
+
76
+ confirm.hide();
77
+ await waitUntil(() => !dropdown.open);
78
+ });
48
79
  });
@@ -6,14 +6,18 @@ import type {ReactiveController, ReactiveControllerHost} from 'lit';
6
6
  import type ZnMenuItem from '../menu-item';
7
7
  import type ZnPopup from '../popup';
8
8
 
9
+ const SUBMENU_GAP = 4;
10
+
9
11
  /** A reactive controller to manage the registration of event listeners for submenus. */
10
12
  export class SubmenuController implements ReactiveController {
13
+ private static readonly openSubmenus = new WeakMap<Element, SubmenuController>();
11
14
  private host: ReactiveControllerHost & ZnMenuItem;
12
15
  private popupRef: Ref<ZnPopup> = createRef();
13
16
  private enableSubmenuTimer = -1;
14
17
  private isConnected = false;
15
18
  private isPopupConnected = false;
16
19
  private skidding = 0;
20
+ private distance = 0;
17
21
  private readonly hasSlotController: HasSlotController;
18
22
  private readonly localize: LocalizeController;
19
23
  private readonly submenuOpenDelay = 100;
@@ -35,13 +39,13 @@ export class SubmenuController implements ReactiveController {
35
39
  }
36
40
 
37
41
  hostDisconnected() {
42
+ this.disableSubmenu();
38
43
  this.removeListeners();
39
44
  }
40
45
 
41
46
  hostUpdated() {
42
47
  if (this.hasSlotController.test('submenu') && !this.host.disabled) {
43
48
  this.addListeners();
44
- this.updateSkidding();
45
49
  } else {
46
50
  this.removeListeners();
47
51
  }
@@ -210,16 +214,6 @@ export class SubmenuController implements ReactiveController {
210
214
 
211
215
  const {left, top, width, height} = menu.getBoundingClientRect();
212
216
 
213
- const parentMenu = this.host.parentElement;
214
- const parentPanel = parentMenu?.shadowRoot?.querySelector('.menu') ?? parentMenu;
215
- if (parentMenu && parentPanel) {
216
- const parent = parentPanel.getBoundingClientRect();
217
- menu.toggleAttribute('data-extends-below', top + height > parent.bottom + 1);
218
- // Flags the parent's corners the submenu covers, so the parent squares them off.
219
- parentMenu.toggleAttribute('data-submenu-top', top <= parent.top + 1);
220
- parentMenu.toggleAttribute('data-submenu-bottom', top + height >= parent.bottom - 1);
221
- }
222
-
223
217
  this.host.style.setProperty('--safe-triangle-submenu-start-x', `${isRtl ? left + width : left}px`);
224
218
  this.host.style.setProperty('--safe-triangle-submenu-start-y', `${top}px`);
225
219
  this.host.style.setProperty('--safe-triangle-submenu-end-x', `${isRtl ? left + width : left}px`);
@@ -227,21 +221,31 @@ export class SubmenuController implements ReactiveController {
227
221
  };
228
222
 
229
223
  private setSubmenuState(state: boolean) {
224
+ const parent = this.host.parentElement;
225
+ if (state && parent) {
226
+ const sibling = SubmenuController.openSubmenus.get(parent);
227
+ if (sibling && sibling !== this) sibling.disableSubmenu();
228
+ SubmenuController.openSubmenus.set(parent, this);
229
+ // Measured on open, not per update: reading styles forces a style recalc (costly in Safari on large pages).
230
+ this.updateSkidding();
231
+ }
230
232
  if (this.popupRef.value) {
231
233
  if (this.popupRef.value.active !== state) {
232
234
  this.popupRef.value.active = state;
233
235
  this.host.requestUpdate();
234
236
  }
235
237
  }
236
- if (!state) {
237
- this.host.parentElement?.removeAttribute('data-submenu-top');
238
- this.host.parentElement?.removeAttribute('data-submenu-bottom');
238
+ if (!state && parent && SubmenuController.openSubmenus.get(parent) === this) {
239
+ SubmenuController.openSubmenus.delete(parent);
239
240
  }
240
241
  }
241
242
 
242
243
  // Shows the submenu. Supports disabling the opening delay, e.g. for keyboard events that want to set the focus to the
243
244
  // newly opened menu.
244
245
  private enableSubmenu(delay = true) {
246
+ // Mouseover fires again when moving between a row's icon and label.
247
+ // Keep one timer so focusout can cancel every pending opening.
248
+ clearTimeout(this.enableSubmenuTimer);
245
249
  if (delay) {
246
250
  this.enableSubmenuTimer = window.setTimeout(() => {
247
251
  this.setSubmenuState(true);
@@ -256,7 +260,8 @@ export class SubmenuController implements ReactiveController {
256
260
  this.setSubmenuState(false);
257
261
  }
258
262
 
259
- // Calculate the space the top of a menu takes-up, for aligning the popup menu-item with the activating element.
263
+ // Aligns the submenu's first item with the activating item, and places the submenu SUBMENU_GAP outside the
264
+ // parent menu's edge rather than the item's.
260
265
  private updateSkidding(): void {
261
266
  // zn-menu's padding and border sit on its inner `.menu`, not the host.
262
267
  const menu = this.host.parentElement;
@@ -264,6 +269,10 @@ export class SubmenuController implements ReactiveController {
264
269
  if (!panel) return;
265
270
  const style = getComputedStyle(panel);
266
271
  this.skidding = -(parseFloat(style.paddingTop) + parseFloat(style.borderTopWidth) + parseFloat(style.marginTop));
272
+ const isLtr = this.localize.dir() === 'ltr';
273
+ this.distance = parseFloat(isLtr ? style.paddingRight : style.paddingLeft)
274
+ + parseFloat(isLtr ? style.borderRightWidth : style.borderLeftWidth)
275
+ + SUBMENU_GAP;
267
276
  }
268
277
 
269
278
  isExpanded(): boolean {
@@ -287,6 +296,7 @@ export class SubmenuController implements ReactiveController {
287
296
  flip
288
297
  flip-fallback-strategy="best-fit"
289
298
  skidding="${this.skidding}"
299
+ distance="${this.distance}"
290
300
  strategy="fixed"
291
301
  >
292
302
  <slot name="submenu"></slot>
@@ -0,0 +1,12 @@
1
+ import ZnMenuLabel from './menu-label.component';
2
+
3
+ export * from './menu-label.component';
4
+ export default ZnMenuLabel;
5
+
6
+ ZnMenuLabel.define('zn-menu-label');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-menu-label': ZnMenuLabel;
11
+ }
12
+ }
@@ -0,0 +1,30 @@
1
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
2
+ import ZincElement from '../../internal/zinc-element';
3
+
4
+ import styles from './menu-label.scss';
5
+
6
+ /**
7
+ * @summary A heading for a group of items in a `zn-menu`. It is skipped by the menu's keyboard navigation.
8
+ * @documentation https://zinc.style/components/menu
9
+ * @status experimental
10
+ * @since 1.0
11
+ *
12
+ * @slot - The label text.
13
+ *
14
+ * @csspart base - The component's base wrapper.
15
+ *
16
+ * @cssproperty --zn-menu-label-padding - Space around the label.
17
+ * @cssproperty --zn-menu-label-color - The label's text colour.
18
+ */
19
+ export default class ZnMenuLabel extends ZincElement {
20
+ static styles: CSSResultGroup = unsafeCSS(styles);
21
+
22
+ connectedCallback() {
23
+ super.connectedCallback();
24
+ this.setAttribute('role', 'presentation');
25
+ }
26
+
27
+ render() {
28
+ return html`<div part="base" class="menu-label"><slot></slot></div>`;
29
+ }
30
+ }
@@ -0,0 +1,18 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: block;
5
+ user-select: none;
6
+ }
7
+
8
+ .menu-label {
9
+ // Inline padding matches a dropdown zn-menu-item's, so the label lines up with the items' content
10
+ padding: var(--zn-menu-label-padding, 6px var(--zn-spacing-large) 3px);
11
+ font-size: 11px;
12
+ font-weight: var(--zn-font-weight-semibold);
13
+ line-height: 1;
14
+ letter-spacing: .05em;
15
+ text-transform: uppercase;
16
+ white-space: nowrap;
17
+ color: var(--zn-menu-label-color, var(--zn-color-neutral-500));
18
+ }
@@ -0,0 +1,12 @@
1
+ import ZnNavItem from './nav-item.component';
2
+
3
+ export * from './nav-item.component';
4
+ export default ZnNavItem;
5
+
6
+ ZnNavItem.define('zn-nav-item');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-nav-item': ZnNavItem;
11
+ }
12
+ }
@@ -0,0 +1,83 @@
1
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
2
+ import {property} from 'lit/decorators.js';
3
+ import ZincElement from '../../internal/zinc-element';
4
+ import ZnIcon from '../icon';
5
+
6
+ import styles from './nav-item.scss';
7
+
8
+ /**
9
+ * @summary A selectable row in a `zn-nav-list`, with an optional description and count.
10
+ * @documentation https://zinc.style/components/nav-list
11
+ * @status experimental
12
+ * @since 1.0
13
+ *
14
+ * @slot - The item's label.
15
+ *
16
+ * @csspart base - The component's base wrapper.
17
+ * @csspart label - The label, truncated with an ellipsis.
18
+ * @csspart description - The description shown below the label.
19
+ * @csspart count - The count shown at the end of the row.
20
+ * @csspart handle - The drag handle, shown when the list is sortable.
21
+ */
22
+ export default class ZnNavItem extends ZincElement {
23
+ static styles: CSSResultGroup = unsafeCSS(styles);
24
+ static dependencies = {
25
+ 'zn-icon': ZnIcon,
26
+ };
27
+
28
+ /** A count shown at the end of the row, such as the number of entries in the group. */
29
+ @property() count: string;
30
+
31
+ /** A line of detail shown below the label. */
32
+ @property() description: string;
33
+
34
+ private readonly _classObserver = new MutationObserver(() => this._syncSelected());
35
+
36
+ connectedCallback() {
37
+ super.connectedCallback();
38
+ this.setAttribute('role', 'tab');
39
+ if (!this.hasAttribute('tabindex')) {
40
+ this.tabIndex = -1;
41
+ }
42
+ this.addEventListener('keydown', this._handleKeyDown);
43
+ // zn-tabs marks the active trigger with a class rather than an attribute
44
+ this._classObserver.observe(this, {attributes: true, attributeFilter: ['class']});
45
+ this._syncSelected();
46
+ }
47
+
48
+ disconnectedCallback() {
49
+ super.disconnectedCallback();
50
+ this.removeEventListener('keydown', this._handleKeyDown);
51
+ this._classObserver.disconnect();
52
+ }
53
+
54
+ get selected() {
55
+ return this.classList.contains('zn-tb-active');
56
+ }
57
+
58
+ private _syncSelected() {
59
+ this.setAttribute('aria-selected', String(this.selected));
60
+ }
61
+
62
+ private _handleKeyDown = (e: KeyboardEvent) => {
63
+ if (e.key === 'Enter' || e.key === ' ') {
64
+ e.preventDefault();
65
+ this.click();
66
+ }
67
+ };
68
+
69
+ render() {
70
+ return html`
71
+ <div part="base" class="nav-item">
72
+ <zn-icon part="handle" class="nav-item__handle" src="drag_indicator" size="16" aria-hidden="true"></zn-icon>
73
+ <span class="nav-item__text">
74
+ <span part="label" class="nav-item__label"><slot></slot></span>
75
+ ${this.description ? html`<span part="description" class="nav-item__description">${this.description}</span>` : ''}
76
+ </span>
77
+ ${this.count !== undefined && this.count !== null && this.count !== ''
78
+ ? html`<span part="count" class="nav-item__count">${this.count}</span>`
79
+ : ''}
80
+ </div>
81
+ `;
82
+ }
83
+ }
@@ -0,0 +1,128 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: block;
5
+ border-radius: var(--zn-border-radius-medium, var(--zn-border-radius));
6
+ cursor: pointer;
7
+ user-select: none;
8
+ }
9
+
10
+ :host([hidden]) {
11
+ display: none;
12
+ }
13
+
14
+ :host(:focus-visible) {
15
+ outline: 2px solid rgb(var(--zn-primary));
16
+ outline-offset: -2px;
17
+ }
18
+
19
+ .nav-item {
20
+ @include wc.text-style(menu-link);
21
+ display: flex;
22
+ align-items: center;
23
+ gap: var(--zn-spacing-x-small);
24
+ padding: var(--zn-nav-item-padding, 7px 10px);
25
+ border-radius: inherit;
26
+ }
27
+
28
+ :host(:hover) .nav-item {
29
+ background: var(--zn-color-neutral-50);
30
+ }
31
+
32
+ :host(.zn-tb-active) .nav-item {
33
+ background: rgba(var(--zn-primary), 0.08);
34
+ color: rgb(var(--zn-primary));
35
+ font-weight: var(--zn-font-weight-semibold);
36
+ }
37
+
38
+ .nav-item__text {
39
+ display: flex;
40
+ flex: 1 1 0;
41
+ flex-direction: column;
42
+ min-width: 0;
43
+ }
44
+
45
+ .nav-item__label {
46
+ overflow: hidden;
47
+ text-overflow: ellipsis;
48
+ white-space: nowrap;
49
+ }
50
+
51
+ .nav-item__description {
52
+ font-size: var(--zn-font-size-small);
53
+ font-weight: var(--zn-font-weight-normal);
54
+ color: var(--zn-color-neutral-500);
55
+ }
56
+
57
+ .nav-item__count {
58
+ flex: 0 0 auto;
59
+ font-size: var(--zn-font-size-small);
60
+ color: var(--zn-color-neutral-500);
61
+ }
62
+
63
+ // Set by a zn-nav-list with divide
64
+ :host([divide]) {
65
+ border-radius: 0;
66
+ }
67
+
68
+ :host([divide]) .nav-item {
69
+ gap: var(--zn-spacing-small);
70
+ padding: var(--zn-nav-item-padding, var(--zn-spacing-small) var(--zn-spacing-medium));
71
+ }
72
+
73
+ :host([divide]) .nav-item__label {
74
+ font-weight: var(--zn-font-weight-semibold);
75
+ }
76
+
77
+ :host([divide].zn-tb-active) .nav-item {
78
+ background: rgba(var(--zn-primary), 0.06);
79
+ box-shadow: inset 3px 0 0 rgb(var(--zn-primary));
80
+ color: inherit;
81
+ }
82
+
83
+ :host([divide]) .nav-item__count {
84
+ padding: 1px var(--zn-spacing-x-small);
85
+ border-radius: 999px;
86
+ background: var(--zn-color-neutral-100);
87
+ font-weight: var(--zn-font-weight-semibold);
88
+ color: var(--zn-color-neutral-700);
89
+ }
90
+
91
+ .nav-item__handle {
92
+ display: none;
93
+ flex: 0 0 auto;
94
+ margin-inline-start: -4px;
95
+ color: var(--zn-color-neutral-400);
96
+ cursor: grab;
97
+ }
98
+
99
+ // Set by a sortable zn-nav-list
100
+ :host([sortable]) {
101
+ // Its own layer, or Chrome draws the drag image over a white box that shows at the rounded corners
102
+ transform: translate(0, 0);
103
+ // Opaque, or the drag image shows the page through the row
104
+ background: rgb(var(--zn-panel));
105
+ cursor: grab;
106
+ }
107
+
108
+ :host([sortable]) .nav-item__handle {
109
+ display: inline-flex;
110
+ }
111
+
112
+ // The dragged item's slot, matching a zn-priority-list placeholder
113
+ :host([sortable][dragging]) .nav-item,
114
+ :host([sortable][dragging]:hover) .nav-item {
115
+ outline: 1px dashed var(--zn-color-primary-400);
116
+ outline-offset: -1px;
117
+ background: rgba(var(--zn-primary), 0.06);
118
+ box-shadow: none;
119
+
120
+ > * {
121
+ opacity: 0;
122
+ }
123
+ }
124
+
125
+ // Set while dragging to the radius of any card corner the row sits in
126
+ :host([divide][sortable][dragging]) .nav-item {
127
+ border-radius: var(--zn-nav-item-drag-radius, 0);
128
+ }
@@ -0,0 +1,12 @@
1
+ import ZnNavList from './nav-list.component';
2
+
3
+ export * from './nav-list.component';
4
+ export default ZnNavList;
5
+
6
+ ZnNavList.define('zn-nav-list');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-nav-list': ZnNavList;
11
+ }
12
+ }