@kubex/zinc 1.1.184 → 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 (362) 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 +10344 -2583
  6. package/dist/vscode.html-custom-data.json +1102 -125
  7. package/dist/web-types.json +2217 -224
  8. package/dist/zn.d.ts +2306 -417
  9. package/dist/zn.min.css +1 -1
  10. package/dist/zn.min.js +2313 -1635
  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/filter-wrapper.md +20 -0
  33. package/docs/pages/components/icon.md +46 -1
  34. package/docs/pages/components/input.md +30 -11
  35. package/docs/pages/components/item.md +35 -0
  36. package/docs/pages/components/key-value.md +25 -0
  37. package/docs/pages/components/menu.md +74 -7
  38. package/docs/pages/components/nav-item.md +15 -0
  39. package/docs/pages/components/nav-list.md +132 -0
  40. package/docs/pages/components/navbar.md +100 -1
  41. package/docs/pages/components/page.md +242 -74
  42. package/docs/pages/components/priority-list.md +43 -5
  43. package/docs/pages/components/query-builder.md +23 -0
  44. package/docs/pages/components/radio-group.md +33 -1
  45. package/docs/pages/components/radio.md +1 -1
  46. package/docs/pages/components/report-table.md +202 -0
  47. package/docs/pages/components/stat.md +30 -0
  48. package/docs/pages/components/tile.md +11 -0
  49. package/docs/pages/components/tooltip.md +1 -1
  50. package/docs/pages/components/translation-grid.md +86 -0
  51. package/docs/pages/components/vertical-stepper.md +108 -64
  52. package/package.json +2 -1
  53. package/scss/_global-spacing.scss +2 -2
  54. package/scss/_root.scss +11 -171
  55. package/scss/boot.scss +14 -0
  56. package/scss/mixins/_helper-mixins.scss +24 -2
  57. package/scss/mixins/_motion-mixins.scss +126 -0
  58. package/scss/mixins/_spacing-mixins.scss +4 -3
  59. package/scss/mixins/_tab-indicator-mixins.scss +12 -0
  60. package/scss/mixins/_typography-mixins.scss +1 -1
  61. package/scss/mixins/index.scss +14 -0
  62. package/scss/shared/_base.scss +32 -1
  63. package/scss/shared/_button-mixin.scss +7 -5
  64. package/scss/shared/_table.scss +35 -4
  65. package/scss/shared/nav.scss +4 -0
  66. package/scss/shared/shimmer.scss +1 -1
  67. package/scss/table-controls.scss +206 -0
  68. package/scss/themes/_dark.scss +1 -3
  69. package/scss/themes/_index.scss +1 -1
  70. package/scss/themes/_light.scss +46 -6
  71. package/scss/themes/_modes.scss +11 -11
  72. package/scss/themes/_openbyte.scss +944 -0
  73. package/scss/themes/_typography.scss +4 -2
  74. package/scss/variables/index.scss +0 -9
  75. package/src/components/alert/alert.component.ts +14 -4
  76. package/src/components/alert/alert.scss +55 -69
  77. package/src/components/alert/alert.test.ts +8 -0
  78. package/src/components/animated-button/animated-button.component.ts +3 -2
  79. package/src/components/animated-button/animated-button.scss +6 -23
  80. package/src/components/animated-button/animated-button.test.ts +4 -3
  81. package/src/components/avatar-group/avatar-group.component.ts +84 -0
  82. package/src/components/avatar-group/avatar-group.scss +54 -0
  83. package/src/components/avatar-group/avatar-group.test.ts +59 -0
  84. package/src/components/avatar-group/index.ts +12 -0
  85. package/src/components/badge/badge.component.ts +49 -0
  86. package/src/components/badge/badge.scss +80 -0
  87. package/src/components/badge/badge.test.ts +34 -0
  88. package/src/components/badge/index.ts +12 -0
  89. package/src/components/bulk-actions/bulk-actions.component.ts +14 -2
  90. package/src/components/button/button.component.ts +242 -11
  91. package/src/components/button/button.scss +133 -25
  92. package/src/components/button/button.test.ts +122 -0
  93. package/src/components/button-menu/button-menu.component.ts +32 -11
  94. package/src/components/button-menu/button-menu.scss +5 -1
  95. package/src/components/channel-tile/channel-tile.component.ts +34 -27
  96. package/src/components/channel-tile/channel-tile.scss +76 -43
  97. package/src/components/chart/builders.test.ts +46 -0
  98. package/src/components/chart/builders.ts +27 -3
  99. package/src/components/chart/chart-live.test.ts +4 -6
  100. package/src/components/chart/chart.component.ts +125 -5
  101. package/src/components/chart/chart.scss +121 -0
  102. package/src/components/chart/chart.test.ts +81 -0
  103. package/src/components/chat-message/chat-message.component.ts +21 -1
  104. package/src/components/chat-message/chat-message.scss +13 -2
  105. package/src/components/chat-message/chat-message.test.ts +9 -0
  106. package/src/components/checkbox/checkbox.component.ts +61 -27
  107. package/src/components/checkbox/checkbox.scss +58 -25
  108. package/src/components/checkbox-group/checkbox-group.component.ts +7 -1
  109. package/src/components/chip/chip.component.ts +11 -1
  110. package/src/components/chip/chip.scss +91 -26
  111. package/src/components/chip/chip.test.ts +17 -0
  112. package/src/components/collapsible/collapsible.component.ts +17 -3
  113. package/src/components/collapsible/collapsible.scss +19 -10
  114. package/src/components/color-picker/color-picker.component.ts +277 -0
  115. package/src/components/color-picker/color-picker.scss +141 -0
  116. package/src/components/color-picker/color-picker.test.ts +57 -0
  117. package/src/components/color-picker/index.ts +12 -0
  118. package/src/components/cols/cols.component.ts +17 -3
  119. package/src/components/cols/cols.scss +24 -13
  120. package/src/components/cols/cols.test.ts +33 -0
  121. package/src/components/confirm/confirm.component.ts +20 -6
  122. package/src/components/confirm/confirm.test.ts +52 -0
  123. package/src/components/content-block/content-block.component.ts +38 -9
  124. package/src/components/content-block/content-block.scss +11 -5
  125. package/src/components/content-block/content-block.test.ts +26 -0
  126. package/src/components/copy-button/copy-button.component.ts +2 -2
  127. package/src/components/copy-button/copy-button.scss +17 -4
  128. package/src/components/data-select/data-select.component.ts +3 -1
  129. package/src/components/data-table/data-table.component.ts +364 -142
  130. package/src/components/data-table/data-table.scss +133 -60
  131. package/src/components/data-table/data-table.test.ts +356 -4
  132. package/src/components/data-table-filter/data-table-filter.component.ts +426 -406
  133. package/src/components/data-table-filter/data-table-filter.scss +176 -148
  134. package/src/components/data-table-filter/data-table-filter.test.ts +271 -273
  135. package/src/components/data-table-search/data-table-search.component.ts +4 -2
  136. package/src/components/data-table-search/data-table-search.scss +8 -1
  137. package/src/components/data-table-search/data-table-search.test.ts +29 -0
  138. package/src/components/date-range/date-range-math.test.ts +78 -0
  139. package/src/components/date-range/date-range-math.ts +105 -0
  140. package/src/components/date-range/date-range.component.ts +375 -0
  141. package/src/components/date-range/date-range.scss +272 -0
  142. package/src/components/date-range/date-range.test.ts +247 -0
  143. package/src/components/date-range/index.ts +12 -0
  144. package/src/components/datepicker/datepicker.component.ts +44 -7
  145. package/src/components/datepicker/datepicker.scss +9 -0
  146. package/src/components/datepicker/datepicker.test.ts +2 -2
  147. package/src/components/dialog/dialog.component.ts +38 -19
  148. package/src/components/dialog/dialog.scss +65 -36
  149. package/src/components/dialog/dialog.test.ts +14 -0
  150. package/src/components/diff/diff.component.ts +55 -0
  151. package/src/components/diff/diff.scss +46 -0
  152. package/src/components/diff/diff.test.ts +15 -0
  153. package/src/components/diff/index.ts +12 -0
  154. package/src/components/diff-row/diff-row.component.ts +75 -0
  155. package/src/components/diff-row/diff-row.scss +70 -0
  156. package/src/components/diff-row/diff-row.test.ts +37 -0
  157. package/src/components/diff-row/index.ts +12 -0
  158. package/src/components/dropdown/dropdown.component.ts +12 -10
  159. package/src/components/dropdown/dropdown.scss +2 -0
  160. package/src/components/editor/editor.component.ts +159 -11
  161. package/src/components/editor/editor.scss +250 -1
  162. package/src/components/editor/editor.test.ts +31 -3
  163. package/src/components/editor/modules/ai/panel/ai-panel.scss +0 -1
  164. package/src/components/editor/modules/attachment/attachment.ts +53 -31
  165. package/src/components/editor/modules/context-menu/context-menu.ts +17 -0
  166. package/src/components/editor/modules/dialog/dialog.component.ts +23 -1
  167. package/src/components/editor/modules/dialog/dialog.test.ts +28 -0
  168. package/src/components/editor/modules/emoji/emoji.ts +4 -5
  169. package/src/components/editor/modules/merge-field/merge-field.ts +83 -0
  170. package/src/components/editor/modules/toolbar/toolbar.component.ts +121 -68
  171. package/src/components/editor/modules/toolbar/toolbar.scss +38 -0
  172. package/src/components/editor/modules/toolbar/toolbar.ts +25 -1
  173. package/src/components/empty-state/empty-state.component.ts +6 -1
  174. package/src/components/empty-state/empty-state.scss +21 -4
  175. package/src/components/expanding-action/expanding-action.component.ts +22 -34
  176. package/src/components/expanding-action/expanding-action.scss +3 -45
  177. package/src/components/expanding-action/expanding-action.test.ts +2 -1
  178. package/src/components/file/file.component.ts +30 -2
  179. package/src/components/file/file.scss +6 -0
  180. package/src/components/filter-wrapper/filter-wrapper.component.ts +45 -10
  181. package/src/components/filter-wrapper/filter-wrapper.test.ts +58 -2
  182. package/src/components/flow-builder/flow-builder.component.ts +36 -3
  183. package/src/components/flow-builder/flow-builder.scss +0 -6
  184. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +8 -0
  185. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +10 -5
  186. package/src/components/flow-builder/modules/flow-node/flow-node.component.ts +17 -0
  187. package/src/components/flow-builder/modules/flow-node/flow-node.scss +10 -0
  188. package/src/components/form-actions/form-actions.component.ts +48 -2
  189. package/src/components/form-actions/form-actions.scss +1 -1
  190. package/src/components/form-group/form-group.component.ts +10 -3
  191. package/src/components/form-group/form-group.scss +37 -4
  192. package/src/components/form-group/form-group.test.ts +10 -0
  193. package/src/components/header/header.component.ts +11 -4
  194. package/src/components/header/header.scss +47 -5
  195. package/src/components/hover-container/hover-container.component.ts +4 -5
  196. package/src/components/icon/icon.component.ts +95 -9
  197. package/src/components/icon/icon.scss +70 -6
  198. package/src/components/icon/icon.test.ts +55 -0
  199. package/src/components/icon-picker/icon-picker.component.ts +35 -1
  200. package/src/components/inline-edit/inline-edit.component.ts +38 -8
  201. package/src/components/inline-edit/inline-edit.scss +128 -19
  202. package/src/components/input/input.component.ts +173 -297
  203. package/src/components/input/input.scss +65 -43
  204. package/src/components/input/input.test.ts +86 -4
  205. package/src/components/item/item.component.ts +12 -0
  206. package/src/components/item/item.scss +102 -3
  207. package/src/components/item/item.test.ts +23 -0
  208. package/src/components/key/key.component.ts +2 -2
  209. package/src/components/key/key.scss +11 -0
  210. package/src/components/key-value/index.ts +12 -0
  211. package/src/components/key-value/key-value.component.ts +160 -0
  212. package/src/components/key-value/key-value.scss +20 -0
  213. package/src/components/key-value/key-value.test.ts +22 -0
  214. package/src/components/markdown-editor/markdown-editor.component.ts +8 -1
  215. package/src/components/menu/menu.component.ts +21 -2
  216. package/src/components/menu/menu.scss +43 -23
  217. package/src/components/menu/menu.test.ts +33 -0
  218. package/src/components/menu-item/menu-item.component.ts +13 -2
  219. package/src/components/menu-item/menu-item.scss +56 -23
  220. package/src/components/menu-item/menu-item.test.ts +31 -0
  221. package/src/components/menu-item/submenu-controller.ts +25 -15
  222. package/src/components/menu-label/index.ts +12 -0
  223. package/src/components/menu-label/menu-label.component.ts +30 -0
  224. package/src/components/menu-label/menu-label.scss +18 -0
  225. package/src/components/nav-item/index.ts +12 -0
  226. package/src/components/nav-item/nav-item.component.ts +83 -0
  227. package/src/components/nav-item/nav-item.scss +128 -0
  228. package/src/components/nav-list/index.ts +12 -0
  229. package/src/components/nav-list/nav-list.component.ts +313 -0
  230. package/src/components/nav-list/nav-list.scss +87 -0
  231. package/src/components/nav-list/nav-list.test.ts +250 -0
  232. package/src/components/navbar/navbar.component.ts +235 -171
  233. package/src/components/navbar/navbar.scss +333 -169
  234. package/src/components/navbar/navbar.test.ts +63 -143
  235. package/src/components/page/page.component.ts +114 -29
  236. package/src/components/page/page.scss +223 -95
  237. package/src/components/page/page.test.ts +214 -3
  238. package/src/components/page-builder/page-builder.component.ts +51 -5
  239. package/src/components/page-builder/page-builder.scss +6 -1
  240. package/src/components/page-nav/page-nav.component.ts +25 -3
  241. package/src/components/page-nav/page-nav.scss +10 -2
  242. package/src/components/pagination/pagination.scss +1 -1
  243. package/src/components/panel/panel.component.ts +14 -13
  244. package/src/components/panel/panel.scss +14 -10
  245. package/src/components/panel/panel.test.ts +42 -0
  246. package/src/components/popup/popup.component.ts +20 -13
  247. package/src/components/popup/popup.test.ts +21 -1
  248. package/src/components/priority-list/priority-list.component.ts +157 -172
  249. package/src/components/priority-list/priority-list.scss +113 -17
  250. package/src/components/priority-list/priority-list.test.ts +301 -3
  251. package/src/components/progress-bar/progress-bar.component.ts +1 -1
  252. package/src/components/progress-bar/progress-bar.scss +16 -4
  253. package/src/components/progress-tile/progress-tile.scss +1 -1
  254. package/src/components/query-builder/query-builder.component.ts +85 -10
  255. package/src/components/query-builder/query-builder.scss +7 -1
  256. package/src/components/query-builder/query-builder.test.ts +40 -0
  257. package/src/components/radio/radio.component.ts +57 -18
  258. package/src/components/radio/radio.scss +101 -26
  259. package/src/components/radio-group/radio-group.component.ts +45 -7
  260. package/src/components/radio-group/radio-group.scss +17 -0
  261. package/src/components/radio-group/radio-group.test.ts +63 -2
  262. package/src/components/rating/rating.component.ts +23 -0
  263. package/src/components/rating/rating.scss +1 -1
  264. package/src/components/remarkd-editor/remarkd-editor.component.ts +60 -5
  265. package/src/components/remarkd-editor/remarkd-editor.scss +12 -4
  266. package/src/components/report-table/index.ts +12 -0
  267. package/src/components/report-table/report-format.test.ts +86 -0
  268. package/src/components/report-table/report-format.ts +72 -0
  269. package/src/components/report-table/report-math.test.ts +74 -0
  270. package/src/components/report-table/report-math.ts +252 -0
  271. package/src/components/report-table/report-table.component.ts +681 -0
  272. package/src/components/report-table/report-table.scss +328 -0
  273. package/src/components/report-table/report-table.test.ts +702 -0
  274. package/src/components/reveal/reveal.component.ts +15 -1
  275. package/src/components/reveal/reveal.scss +5 -0
  276. package/src/components/schedule-builder/schedule-builder.component.ts +23 -8
  277. package/src/components/scroll-container/scroll-container.component.ts +19 -1
  278. package/src/components/scroll-container/scroll-container.scss +6 -1
  279. package/src/components/select/select.component.ts +52 -36
  280. package/src/components/select/select.scss +42 -25
  281. package/src/components/select/select.test.ts +14 -2
  282. package/src/components/settings-container/settings-container.scss +18 -5
  283. package/src/components/sidebar/sidebar.component.ts +8 -1
  284. package/src/components/sidebar/sidebar.scss +6 -1
  285. package/src/components/skeleton/skeleton.component.ts +3 -3
  286. package/src/components/skeleton/skeleton.scss +6 -6
  287. package/src/components/skeleton/skeleton.test.ts +9 -0
  288. package/src/components/slash-menu/slash-menu.scss +1 -1
  289. package/src/components/slideout/slideout.component.ts +20 -3
  290. package/src/components/slideout/slideout.scss +13 -6
  291. package/src/components/slideout/slideout.test.ts +19 -0
  292. package/src/components/split-button/split-button.component.ts +1 -1
  293. package/src/components/split-pane/split-pane.component.ts +71 -8
  294. package/src/components/split-pane/split-pane.scss +145 -41
  295. package/src/components/split-pane/split-pane.test.ts +23 -3
  296. package/src/components/stat/stat.component.ts +209 -14
  297. package/src/components/stat/stat.scss +305 -5
  298. package/src/components/stat/stat.test.ts +143 -2
  299. package/src/components/status-indicator/status-indicator.scss +22 -21
  300. package/src/components/stepper/stepper.scss +3 -3
  301. package/src/components/tab/tab.component.ts +1 -0
  302. package/src/components/table/table.component.ts +12 -1
  303. package/src/components/table/table.scss +21 -13
  304. package/src/components/table/table.test.ts +17 -0
  305. package/src/components/tabs/tabs.component.ts +150 -37
  306. package/src/components/tabs/tabs.scss +48 -7
  307. package/src/components/tabs/tabs.test.ts +169 -0
  308. package/src/components/textarea/textarea.component.ts +25 -3
  309. package/src/components/textarea/textarea.scss +10 -0
  310. package/src/components/textarea/textarea.test.ts +8 -4
  311. package/src/components/theme-editor/theme-editor.scss +0 -6
  312. package/src/components/tile/tile.component.ts +32 -2
  313. package/src/components/tile/tile.scss +40 -7
  314. package/src/components/tile/tile.test.ts +10 -0
  315. package/src/components/toggle/toggle.component.ts +23 -7
  316. package/src/components/toggle/toggle.scss +36 -29
  317. package/src/components/toggle/toggle.test.ts +17 -0
  318. package/src/components/tooltip/tooltip.component.ts +3 -0
  319. package/src/components/tooltip/tooltip.scss +11 -6
  320. package/src/components/tooltip/tooltip.test.ts +12 -0
  321. package/src/components/translation-field/index.ts +12 -0
  322. package/src/components/translation-field/translation-field.component.ts +55 -0
  323. package/src/components/translation-field/translation-field.scss +101 -0
  324. package/src/components/translation-fields/index.ts +12 -0
  325. package/src/components/translation-fields/translation-fields.component.ts +80 -0
  326. package/src/components/translation-fields/translation-fields.scss +60 -0
  327. package/src/components/translation-grid/index.ts +12 -0
  328. package/src/components/translation-grid/translation-grid.component.ts +157 -0
  329. package/src/components/translation-grid/translation-grid.scss +138 -0
  330. package/src/components/translation-grid/translation-grid.test.ts +28 -0
  331. package/src/components/vertical-stepper/vertical-stepper.component.ts +35 -9
  332. package/src/components/vertical-stepper/vertical-stepper.scss +110 -39
  333. package/src/components/vertical-stepper/vertical-stepper.test.ts +35 -0
  334. package/src/components/well/well.scss +2 -2
  335. package/src/events/events.ts +2 -0
  336. package/src/events/zn-chart-click.ts +13 -0
  337. package/src/events/zn-report-change.ts +7 -0
  338. package/src/form-control.scss +36 -3
  339. package/src/internal/anchored-popover.ts +175 -0
  340. package/src/internal/animate.ts +19 -5
  341. package/src/internal/cosmic-border.ts +15 -0
  342. package/src/internal/form.ts +1 -1
  343. package/src/internal/hover-intent.ts +15 -0
  344. package/src/internal/input-modality.ts +15 -0
  345. package/src/internal/pointer-intent.ts +37 -0
  346. package/src/internal/reorder.ts +625 -0
  347. package/src/internal/scroll.ts +51 -3
  348. package/src/internal/selection-card.ts +1 -1
  349. package/src/internal/tab-indicator.ts +92 -0
  350. package/src/internal/table-sort.ts +25 -0
  351. package/src/internal/table-tabs.ts +108 -0
  352. package/src/internal/test-drag.ts +35 -0
  353. package/src/internal/theme-openbyte.test.ts +126 -0
  354. package/src/internal/theme.ts +4 -4
  355. package/src/internal/zinc-element.ts +2 -2
  356. package/src/selection-card.scss +25 -0
  357. package/src/types/web-test-runner-commands.d.ts +1 -0
  358. package/src/utilities/color.test.ts +43 -0
  359. package/src/utilities/color.ts +189 -0
  360. package/src/zinc.ts +14 -0
  361. package/.github/workflows/eleventy_build.yml +0 -42
  362. package/scss/themes/_aura.scss +0 -114
@@ -0,0 +1,80 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: inline-flex;
5
+ vertical-align: middle;
6
+ }
7
+
8
+ .badge {
9
+ --badge-fg: var(--zn-color-neutral-fg);
10
+ --badge-bg: var(--zn-color-neutral-bg);
11
+ --badge-line: var(--zn-color-neutral-line);
12
+ --badge-solid: var(--zn-color-neutral-solid);
13
+ --badge-ink: 255, 255, 255;
14
+
15
+ box-sizing: border-box;
16
+ display: inline-flex;
17
+ align-items: center;
18
+ gap: var(--zn-badge-gap, 4.8px);
19
+ height: var(--zn-badge-height, 20px);
20
+ padding-inline: var(--zn-badge-padding-inline, 7.2px);
21
+ font-family: var(--zn-font-family-sans);
22
+ font-size: var(--zn-badge-font-size, 11px);
23
+ font-weight: var(--zn-font-weight-semibold);
24
+ line-height: 1;
25
+ white-space: nowrap;
26
+ color: var(--badge-fg);
27
+ background: var(--badge-bg);
28
+ border: 1px solid var(--badge-line);
29
+ border-radius: var(--zn-badge-border-radius, var(--zn-border-radius));
30
+ }
31
+
32
+ .badge--large {
33
+ height: var(--zn-badge-large-height, 24px);
34
+ padding-inline: var(--zn-badge-large-padding-inline, 9.6px);
35
+ font-size: var(--zn-badge-large-font-size, 12px);
36
+ }
37
+
38
+ @each $type in (success, warning, danger, info, ai) {
39
+ .badge--#{$type} {
40
+ --badge-fg: var(--zn-color-#{$type}-fg);
41
+ --badge-bg: var(--zn-color-#{$type}-bg);
42
+ --badge-line: var(--zn-color-#{$type}-line);
43
+ --badge-solid: var(--zn-color-#{$type}-solid);
44
+ }
45
+ }
46
+
47
+ .badge--warning {
48
+ --badge-ink: var(--zn-color-on-warning, 255, 255, 255);
49
+ }
50
+
51
+ .badge--ai {
52
+ --badge-ink: var(--zn-color-on-ai, 255, 255, 255);
53
+ }
54
+
55
+ .badge--solid {
56
+ color: rgb(var(--badge-ink));
57
+ background: var(--badge-solid);
58
+ border-color: var(--badge-solid);
59
+ }
60
+
61
+ .badge--dot::before {
62
+ content: "";
63
+ flex: none;
64
+ width: 6.4px;
65
+ height: 6.4px;
66
+ border-radius: 50%;
67
+ background: var(--badge-solid);
68
+ }
69
+
70
+ .badge--solid.badge--dot::before {
71
+ background: currentColor;
72
+ }
73
+
74
+ .badge__icon {
75
+ flex: none;
76
+
77
+ &::part(icon) {
78
+ stroke-width: 1.75;
79
+ }
80
+ }
@@ -0,0 +1,34 @@
1
+ import '../../../dist/zn.min.js';
2
+ import { expect, fixture, html } from '@open-wc/testing';
3
+
4
+ const base = (el: HTMLElement) => el.shadowRoot!.querySelector<HTMLElement>('[part="base"]')!;
5
+
6
+ describe('<zn-badge>', () => {
7
+ it('should render a component', async () => {
8
+ const el = await fixture(html` <zn-badge></zn-badge> `);
9
+
10
+ expect(el).to.exist;
11
+ });
12
+
13
+ it('applies the type, size, solid and dot classes', async () => {
14
+ const el = await fixture<HTMLElement>(html`<zn-badge type="success" size="large" solid dot>Large</zn-badge>`);
15
+
16
+ expect([...base(el).classList]).to.include.members(
17
+ ['badge--success', 'badge--large', 'badge--solid', 'badge--dot']);
18
+ });
19
+
20
+ it('shows the sparkle icon only on ai badges', async () => {
21
+ const ai = await fixture<HTMLElement>(html`<zn-badge type="ai">AI suggested</zn-badge>`);
22
+ const info = await fixture<HTMLElement>(html`<zn-badge type="info">Trial</zn-badge>`);
23
+
24
+ expect(ai.shadowRoot!.querySelector('zn-icon')).to.exist;
25
+ expect(info.shadowRoot!.querySelector('zn-icon')).to.not.exist;
26
+ });
27
+
28
+ it('fills a solid badge with its type colour', async () => {
29
+ const el = await fixture<HTMLElement>(html`
30
+ <zn-badge type="danger" solid style="--zn-color-danger-solid: rgb(217, 46, 75)">Urgent</zn-badge>`);
31
+
32
+ expect(getComputedStyle(base(el)).backgroundColor).to.equal('rgb(217, 46, 75)');
33
+ });
34
+ });
@@ -0,0 +1,12 @@
1
+ import ZnBadge from './badge.component';
2
+
3
+ export * from './badge.component';
4
+ export default ZnBadge;
5
+
6
+ ZnBadge.define('zn-badge');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-badge': ZnBadge;
11
+ }
12
+ }
@@ -147,6 +147,7 @@ export default class ZnBulkActions extends ZincElement {
147
147
  icon="delete"
148
148
  icon-size="24"
149
149
  color="transparent"
150
+ label="Remove rule"
150
151
  @click="${(e: Event) => this._removeRule(uniqueId, e)}">
151
152
  </zn-button>`;
152
153
 
@@ -260,21 +261,32 @@ export default class ZnBulkActions extends ZincElement {
260
261
  return position;
261
262
  }
262
263
 
263
- private _changeRule(id: string, event: ZnChangeEvent) {
264
+ private async _changeRule(id: string, event: ZnChangeEvent) {
264
265
  // remove the element from the dom
265
266
  const pos: number = this._getRulePosition(id);
266
267
  const select = event.target as ZnSelect;
268
+ const hadFocus = select.matches(':focus-within');
267
269
  select.popup.active = false;
268
270
  select?.parentElement?.remove();
269
271
  // recreate the element based on the selected value;
270
272
  this._removeRule(id, event as unknown as Event);
271
273
  this._addRule(event as unknown as Event, '', pos);
274
+
275
+ const replacement = this.container.children[pos]?.querySelector<ZnSelect>('.query-builder__key');
276
+ if (hadFocus && replacement) {
277
+ await replacement.updateComplete;
278
+ replacement.focus();
279
+ }
272
280
  }
273
281
 
274
282
  private _removeRule(id: string, event: Event) {
275
283
  this._selectedRules.delete(id);
276
284
  const button = event.target as ZnButton;
277
- button?.closest('.query-builder__row')?.remove();
285
+ const row = button?.closest('.query-builder__row');
286
+ const hadFocus = row?.matches(':focus-within');
287
+ const neighbour = row?.nextElementSibling?.matches('.query-builder__row') ? row.nextElementSibling : row?.previousElementSibling;
288
+ row?.remove();
289
+ if (hadFocus) (neighbour?.querySelector<ZnButton>('.query-builder__remove')?.button ?? this.addRule).focus();
278
290
  this._handleChange();
279
291
  }
280
292
 
@@ -4,7 +4,7 @@ import {FormControlController, validValidityState} from "../../internal/form";
4
4
  import {HasSlotController} from '../../internal/slot';
5
5
  import {html, literal} from 'lit/static-html.js';
6
6
  import {ifDefined} from 'lit/directives/if-defined.js';
7
- import {property, query, queryAll} from 'lit/decorators.js';
7
+ import {property, query, queryAll, state} from 'lit/decorators.js';
8
8
  import {styleMap} from "lit/directives/style-map.js";
9
9
  import {watch} from '../../internal/watch';
10
10
  import ZincElement from '../../internal/zinc-element';
@@ -12,6 +12,7 @@ import ZnDropdown from "../dropdown";
12
12
  import ZnIcon from "../icon";
13
13
  import ZnTooltip from "../tooltip";
14
14
  import type {IconColor, IconLibrary} from "../icon";
15
+ import type ZnMenu from "../menu";
15
16
  import type {ZincFormControl} from '../../internal/zinc-element';
16
17
 
17
18
  import sharedStyles from '../../../scss/shared/index.scss';
@@ -23,6 +24,7 @@ import styles from './button.scss';
23
24
  * @status stable
24
25
  * @since 2.0
25
26
  *
27
+ * @dependency zn-dropdown
26
28
  * @dependency zn-icon
27
29
  * @dependency zn-tooltip
28
30
  *
@@ -34,6 +36,7 @@ import styles from './button.scss';
34
36
  * @slot prefix - A presentational prefix icon or similar element.
35
37
  * @slot suffix - A presentational suffix icon or similar element.
36
38
  * @slot cancel - Slot for custom cancel button/content when autoClick is active.
39
+ * @slot menu - A `<zn-menu>` of advanced options, opened by a long press, a right click, or ArrowDown on the button.
37
40
  *
38
41
  * @csspart base - The component's base wrapper.
39
42
  * @csspart prefix - The container that wraps the prefix.
@@ -45,26 +48,43 @@ import styles from './button.scss';
45
48
  export default class ZnButton extends ZincElement implements ZincFormControl {
46
49
  static styles: CSSResultGroup = [unsafeCSS(sharedStyles), unsafeCSS(styles)];
47
50
  static dependencies = {
51
+ 'zn-dropdown': ZnDropdown,
48
52
  'zn-tooltip': ZnTooltip,
49
53
  'zn-icon': ZnIcon
50
54
  };
51
55
 
52
56
  private readonly formControlController = new FormControlController(this);
53
- private readonly hasSlotController = new HasSlotController(this, '[default]');
57
+ private readonly hasSlotController = new HasSlotController(this, '[default]', 'menu');
54
58
  private _autoClickTimeout: number | undefined;
55
59
  private _loadingState = {
56
60
  countdown: null as number | null,
57
61
  interval: undefined as number | undefined,
58
62
  };
59
63
 
64
+ // Long press menu
65
+ private _longPressTimeout: number | undefined;
66
+ private _longPressOrigin: { x: number, y: number } | null = null;
67
+ /** The pointer that opened the menu is still down, so releasing it over an item selects that item. */
68
+ private _menuPointerHeld = false;
69
+ /** Swallows the click that ends a long press, so the button's own action does not run. */
70
+ private _suppressClick = false;
71
+ private _menuHadFocus = false;
72
+
73
+ @state() private menuOpen = false;
74
+
60
75
  @query('.button') button: HTMLButtonElement;
76
+ @query('.button__menu') menuDropdown: ZnDropdown;
61
77
  @queryAll('.loading-countdown') countdownContainer: HTMLElement[];
62
78
 
63
- @property({}) color: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' |
79
+ /** `ai` is reserved for actions that invoke or act on AI-generated content. */
80
+ @property({}) color: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | 'ai' |
64
81
  'transparent' | 'star' | (string & Record<never, never>) = 'default';
82
+ @property() size: 'small' | 'medium' | 'large' = 'medium';
65
83
  @property({attribute: 'hover-color'}) hoverColor: string;
66
84
  @property({type: Boolean}) text = false;
67
85
  @property({type: Boolean}) outline = false;
86
+ /** Keeps the filled look where a container forces `text`, such as a page header's action menu. */
87
+ @property({type: Boolean}) solid = false;
68
88
  @property({type: Boolean}) disabled = false;
69
89
  @property({type: Boolean}) grow = false;
70
90
  @property({type: Boolean}) square = false;
@@ -89,6 +109,13 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
89
109
  @property({type: Boolean, reflect: true}) pill = false;
90
110
  @property({type: Boolean, attribute: 'panel-bg'}) panelBackground = false;
91
111
 
112
+ /** How long, in milliseconds, the button must be held to open the `menu` slot. */
113
+ @property({type: Number, attribute: 'long-press-delay'}) longPressDelay = 500;
114
+
115
+ /** Where the `menu` slot opens relative to the button. */
116
+ @property({attribute: 'menu-placement'}) menuPlacement: 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' |
117
+ 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' = 'bottom-start';
118
+
92
119
  @property({attribute: 'dropdown-closer', type: Boolean}) dropdownCloser = false;
93
120
 
94
121
  @property({type: Number}) notification: number;
@@ -131,6 +158,12 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
131
158
  /** Toggle state, forwarded to the inner button's `aria-pressed`. */
132
159
  @property({attribute: 'aria-pressed'}) pressed: 'true' | 'false' | 'mixed';
133
160
 
161
+ /** Popup state, forwarded to the inner button's `aria-expanded`. */
162
+ @property({attribute: 'aria-expanded'}) expanded: 'true' | 'false';
163
+
164
+ /** Popup type, forwarded to the inner button's `aria-haspopup`. */
165
+ @property({attribute: 'aria-haspopup'}) hasPopup: string;
166
+
134
167
  // Auto Click Specific
135
168
  @property({type: Boolean, attribute: 'auto-click'}) autoClick = false;
136
169
  @property({type: Number, attribute: 'auto-click-delay'}) autoClickDelay = 2000;
@@ -141,6 +174,12 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
141
174
  }) loadingTextPosition: 'left' | 'right' | 'center' | string = 'center';
142
175
  @property({type: Boolean}) loading = false;
143
176
 
177
+ /** Shows a spinner and ignores clicks, e.g. while a request is in flight. */
178
+ @property({type: Boolean, reflect: true}) processing = false;
179
+
180
+ /** Replaces the label while processing. */
181
+ @property({attribute: 'processing-text'}) processingText = '';
182
+
144
183
  get validity() {
145
184
  if (this._isButton() && this.button) {
146
185
  return (this.button as HTMLButtonElement).validity;
@@ -163,9 +202,16 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
163
202
  }
164
203
  }
165
204
 
205
+ connectedCallback() {
206
+ super.connectedCallback();
207
+ this.addEventListener('click', this.handleHostClickCapture, {capture: true});
208
+ }
209
+
166
210
  disconnectedCallback() {
167
211
  super.disconnectedCallback();
168
212
  this.teardownAutoClick();
213
+ this.cancelLongPress();
214
+ this.removeEventListener('click', this.handleHostClickCapture, {capture: true});
169
215
  }
170
216
 
171
217
  @watch('autoClick')
@@ -242,7 +288,7 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
242
288
  }
243
289
 
244
290
  handleClick = () => {
245
- if (this.disabled) {
291
+ if (this.disabled || this.processing) {
246
292
  return;
247
293
  }
248
294
 
@@ -264,13 +310,180 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
264
310
  dropdown?.hide();
265
311
  }
266
312
 
313
+ // Passing the button through carries its name, value and formaction onto the submission.
267
314
  if (this.type === 'submit') {
268
- this.formControlController.submit();
315
+ this.formControlController.submit(this);
269
316
  }
270
317
 
271
318
  if (this.type === 'reset') {
272
- this.formControlController.reset();
319
+ this.formControlController.reset(this);
320
+ }
321
+ }
322
+
323
+ private _hasMenu() {
324
+ return this.hasSlotController.test('menu');
325
+ }
326
+
327
+ private getMenu() {
328
+ return this.querySelector<ZnMenu>(':scope > zn-menu[slot="menu"], :scope > [slot="menu"] zn-menu');
329
+ }
330
+
331
+ /** Opens the advanced options in the `menu` slot. */
332
+ async showMenu() {
333
+ if (!this._hasMenu() || this.disabled || this.processing) return;
334
+ await this.updateComplete;
335
+ await this.menuDropdown?.show();
336
+ }
337
+
338
+ /** Closes the advanced options in the `menu` slot. */
339
+ async hideMenu() {
340
+ await this.menuDropdown?.hide();
341
+ }
342
+
343
+ // Runs before any click listener on the button, including the consumer's own
344
+ private handleHostClickCapture = (event: MouseEvent) => {
345
+ if (!this._suppressClick) return;
346
+
347
+ const menuSlot = this.shadowRoot?.querySelector('slot[name="menu"]');
348
+ const fromMenu = event.composedPath().some(el => (el as Element).assignedSlot === menuSlot);
349
+ if (fromMenu) return;
350
+
351
+ this._suppressClick = false;
352
+ event.preventDefault();
353
+ event.stopImmediatePropagation();
354
+ }
355
+
356
+ private handleMenuPointerDown = (event: PointerEvent) => {
357
+ if (!this._hasMenu() || this.disabled || this.processing || event.button !== 0) return;
358
+
359
+ // Pressing the button while its menu is open only closes the menu, which the dropdown does on mousedown
360
+ if (this.menuOpen) {
361
+ this._suppressClick = true;
362
+ document.addEventListener('pointerup', this.handleMenuPointerUp);
363
+ return;
364
+ }
365
+
366
+ this.cancelLongPress();
367
+ this._longPressOrigin = {x: event.clientX, y: event.clientY};
368
+ this._longPressTimeout = window.setTimeout(() => {
369
+ this._longPressTimeout = undefined;
370
+ this._suppressClick = true;
371
+ this._menuPointerHeld = true;
372
+ this.showMenu().then(r => r);
373
+ }, this.longPressDelay);
374
+
375
+ document.addEventListener('pointermove', this.handleMenuPointerMove);
376
+ document.addEventListener('pointerup', this.handleMenuPointerUp);
377
+ document.addEventListener('pointercancel', this.handleMenuPointerCancel);
378
+ }
379
+
380
+ private handleMenuPointerMove = (event: PointerEvent) => {
381
+ if (this._longPressTimeout === undefined || !this._longPressOrigin) return;
382
+
383
+ const moved = Math.hypot(event.clientX - this._longPressOrigin.x, event.clientY - this._longPressOrigin.y);
384
+ if (moved > 8) {
385
+ this.cancelLongPress();
386
+ }
387
+ }
388
+
389
+ private handleMenuPointerUp = (event: PointerEvent) => {
390
+ const held = this._menuPointerHeld;
391
+ this.cancelLongPress();
392
+
393
+ // Press, drag onto an item and release selects it, as in the macOS Dock
394
+ if (held) {
395
+ const item = document.elementFromPoint(event.clientX, event.clientY)?.closest('zn-menu-item');
396
+ if (item && this.contains(item) && !item.hasAttribute('disabled')) {
397
+ (item as HTMLElement).click();
398
+ }
273
399
  }
400
+
401
+ // A long press on touch ends without a click, so the flag must not outlive this gesture
402
+ if (this._suppressClick) {
403
+ window.setTimeout(() => this._suppressClick = false, 300);
404
+ }
405
+ }
406
+
407
+ private handleMenuPointerCancel = () => {
408
+ this.cancelLongPress();
409
+ this._suppressClick = false;
410
+ }
411
+
412
+ private cancelLongPress() {
413
+ window.clearTimeout(this._longPressTimeout);
414
+ this._longPressTimeout = undefined;
415
+ this._longPressOrigin = null;
416
+ this._menuPointerHeld = false;
417
+ document.removeEventListener('pointermove', this.handleMenuPointerMove);
418
+ document.removeEventListener('pointerup', this.handleMenuPointerUp);
419
+ document.removeEventListener('pointercancel', this.handleMenuPointerCancel);
420
+ }
421
+
422
+ private handleMenuContextMenu = (event: MouseEvent) => {
423
+ if (!this._hasMenu()) return;
424
+
425
+ event.preventDefault();
426
+ // A touch long press also fires contextmenu, after the menu has already opened
427
+ if (!this.menuOpen) {
428
+ this.cancelLongPress();
429
+ this.showMenu().then(r => r);
430
+ }
431
+ }
432
+
433
+ private handleMenuKeyDown = async (event: KeyboardEvent) => {
434
+ if (!this._hasMenu()) return;
435
+
436
+ const opensMenu = event.key === 'ArrowDown' || event.key === 'ContextMenu' || (event.key === 'F10' && event.shiftKey);
437
+ if (!opensMenu) return;
438
+
439
+ event.preventDefault();
440
+ await this.showMenu();
441
+
442
+ const menu = this.getMenu();
443
+ const first = menu?.getAllItems()[0];
444
+ if (menu && first) {
445
+ menu.setCurrentItem(first);
446
+ first.focus();
447
+ }
448
+ }
449
+
450
+ private handleMenuShow = (event: Event) => {
451
+ if (event.target !== this.menuDropdown) return;
452
+ this.menuOpen = true;
453
+ }
454
+
455
+ private handleMenuHide = (event: Event) => {
456
+ if (event.target !== this.menuDropdown) return;
457
+ this.menuOpen = false;
458
+ this._menuHadFocus = !!this.getMenu()?.matches(':focus-within');
459
+ }
460
+
461
+ // The dropdown's anchor is not focusable, so focus returns to the button itself
462
+ private handleMenuAfterHide = (event: Event) => {
463
+ if (event.target !== this.menuDropdown) return;
464
+ if (this._menuHadFocus) {
465
+ this._menuHadFocus = false;
466
+ this.button?.focus();
467
+ }
468
+ }
469
+
470
+ private _renderMenu() {
471
+ if (!this._hasMenu()) {
472
+ // Kept in the tree so adding a menu later fires slotchange
473
+ return html`<slot name="menu" hidden></slot>`;
474
+ }
475
+
476
+ return html`
477
+ <zn-dropdown class="button__menu"
478
+ placement=${this.menuPlacement}
479
+ @zn-show=${this.handleMenuShow}
480
+ @zn-hide=${this.handleMenuHide}
481
+ @zn-after-hide=${this.handleMenuAfterHide}>
482
+ <span slot="trigger" class="button__menu-anchor"></span>
483
+ <div class="button__menu-panel">
484
+ <slot name="menu"></slot>
485
+ </div>
486
+ </zn-dropdown>`;
274
487
  }
275
488
 
276
489
  private _isLink() {
@@ -299,6 +512,8 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
299
512
  return 'rgb(var(--zn-color-success))';
300
513
  case 'warning':
301
514
  return 'rgb(var(--zn-color-warning))';
515
+ case 'ai':
516
+ return 'var(--zn-color-ai-fg)';
302
517
  case 'transparent':
303
518
  return 'inherit';
304
519
  case 'star':
@@ -376,9 +591,10 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
376
591
 
377
592
  protected render(): unknown {
378
593
  const isLink = this._isLink();
594
+ const hasMenu = this._hasMenu();
379
595
  const showCancel = this.loading && this.autoClick;
380
596
  const resolvedIconSize = this.iconSize ? this.iconSize : 20;
381
- const icon = this.icon && !this.loading ? html`
597
+ const icon = this.icon && !this.loading && !this.processing ? html`
382
598
  <zn-icon part="icon" src="${this.icon}" id="xy2" size="${resolvedIconSize}"
383
599
  color="${ifDefined(this.iconColor)}" fill="${ifDefined(this.iconFill)}"
384
600
  library="${ifDefined(this.iconLibrary)}"></zn-icon>`
@@ -411,10 +627,13 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
411
627
  'button--info': this.color === 'info',
412
628
  'button--success': this.color === 'success',
413
629
  'button--warning': this.color === 'warning',
630
+ 'button--ai': this.color === 'ai',
631
+ 'button--small': this.size === 'small',
632
+ 'button--large': this.size === 'large',
414
633
  'button--transparent': this.color === 'transparent',
415
634
  'button--star': this.color === 'star',
416
635
  'button--outline': this.outline,
417
- 'button--text': (this.text && !this.outline),
636
+ 'button--text': (this.text && !this.outline && !this.solid),
418
637
  'button--icon-button': !!this.iconButton,
419
638
  'button--plain': !!this.iconButton && this.plain,
420
639
  'button--pill': this.pill,
@@ -431,6 +650,8 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
431
650
  'button--has-notification': notification !== undefined && notification !== 0,
432
651
  'button--muted-notification': this.mutedNotifications || notification === -2,
433
652
  'button--notification-dot': notification !== undefined && notification < 0,
653
+ 'button--processing': this.processing,
654
+ 'button--has-menu': hasMenu,
434
655
  })}"
435
656
  type="${ifDefined(this.type)}"
436
657
  href="${ifDefined(this.href)}"
@@ -440,15 +661,25 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
440
661
  gaid="${ifDefined(this.gaid)}"
441
662
  aria-label="${ifDefined(ariaLabel)}"
442
663
  aria-pressed="${ifDefined(isLink ? undefined : this.pressed)}"
664
+ aria-expanded="${ifDefined(this.expanded ?? (hasMenu ? String(this.menuOpen) : undefined))}"
665
+ aria-haspopup="${ifDefined(this.hasPopup ?? (hasMenu ? 'menu' : undefined))}"
666
+ draggable="${ifDefined(isLink && hasMenu ? 'false' : undefined)}"
667
+ aria-busy="${this.processing ? 'true' : nothing}"
443
668
  data-notification="${ifDefined(notification)}"
444
669
  disabled="${this.disabled || nothing}"
445
670
  style=${styleMap(buttonStyles)}
446
- @click="${this.handleClick}">
671
+ @click="${this.handleClick}"
672
+ @pointerdown="${this.handleMenuPointerDown}"
673
+ @contextmenu="${this.handleMenuContextMenu}"
674
+ @keydown="${this.handleMenuKeyDown}">
447
675
  ${this.iconPosition === 'left' ? icon : ''}
676
+ ${this.processing ? html`<span part="spinner" class="button__spinner"></span>` : ''}
677
+ ${this.processing && this.processingText ? html`<span class="button__processing-text">${this.processingText}</span>` : ''}
448
678
  <slot part="label"
449
679
  class="${classMap({
450
680
  'button__label': true,
451
- 'button__label--hidden': this.loading
681
+ 'button__label--hidden': this.loading,
682
+ 'button__label--replaced': this.processing && !!this.processingText
452
683
  })}"
453
684
  style="--loading-duration: ${this.autoClickDelay / 1000}s">
454
685
  ${this.content}
@@ -473,7 +704,7 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
473
704
  </zn-tooltip>`;
474
705
  }
475
706
 
476
- return content;
707
+ return html`${content}${this._renderMenu()}`;
477
708
  }
478
709
 
479
710
  private _getLoadingContainer() {