@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
@@ -1,3 +1,4 @@
1
+ import { animateTo } from "../../internal/animate";
1
2
  import { classMap } from "lit/directives/class-map.js";
2
3
  import { type CSSResultGroup, html, type PropertyValues, unsafeCSS } from 'lit';
3
4
  import { defaultValue } from "../../internal/default-value";
@@ -20,6 +21,7 @@ import styles from './toggle.scss';
20
21
  * @dependency zn-tooltip
21
22
  *
22
23
  * @event zn-input - Emitted when the toggle receives input.
24
+ * @event zn-change - Emitted when the toggle is switched on or off.
23
25
  *
24
26
  * @slot - The toggle's label.
25
27
  * @slot description - A description of the toggle's label. Alternatively, you can use the `description` attribute.
@@ -44,6 +46,7 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
44
46
  });
45
47
 
46
48
  @query('input[type="checkbox"]') input: HTMLInputElement;
49
+ @query('.switch__control') knob: HTMLElement;
47
50
 
48
51
  @state() hasFocus: boolean = false;
49
52
 
@@ -98,6 +101,21 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
98
101
  super.firstUpdated(_changedProperties);
99
102
  }
100
103
 
104
+ updated(changedProperties: PropertyValues<this>) {
105
+ super.updated(changedProperties);
106
+ // Skips the first render so a toggle that loads checked doesn't wobble into place.
107
+ if (changedProperties.has('checked') && changedProperties.get('checked') !== undefined) {
108
+ animateTo(this.knob, [
109
+ { scale: '1 1' },
110
+ { scale: '1.35 0.8', offset: 0.3 },
111
+ { scale: '0.85 1.12', offset: 0.55 },
112
+ { scale: '1.06 0.95', offset: 0.72 },
113
+ { scale: '0.98 1.02', offset: 0.86 },
114
+ { scale: '1 1' }
115
+ ], { duration: 500, easing: 'ease-out' });
116
+ }
117
+ }
118
+
101
119
  private handleBlur() {
102
120
  this.hasFocus = false;
103
121
  }
@@ -115,6 +133,7 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
115
133
 
116
134
  private handleClick() {
117
135
  this.checked = !this.checked;
136
+ this.emit('zn-change');
118
137
  if (this.triggerSubmit) {
119
138
  this.formControlController.submit();
120
139
  }
@@ -125,14 +144,11 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
125
144
  }
126
145
 
127
146
  private handleKeyDown(event: KeyboardEvent) {
128
- if (event.key === 'ArrowLeft') {
129
- event.preventDefault();
130
- this.checked = false;
131
- }
147
+ if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
148
+ event.preventDefault();
132
149
 
133
- if (event.key === 'ArrowRight') {
134
- event.preventDefault();
135
- this.checked = true;
150
+ if (this.checked !== (event.key === 'ArrowRight')) {
151
+ this.input.click();
136
152
  }
137
153
  }
138
154
 
@@ -19,28 +19,35 @@
19
19
  }
20
20
 
21
21
  .switch__input-wrapper {
22
+ --track-width: var(--zn-toggle-track-width, 42px);
23
+ --track-height: var(--zn-toggle-track-height, 24px);
24
+ --knob-size: var(--zn-toggle-knob-size, 20.32px);
25
+ --knob-inset: var(--zn-toggle-knob-inset, 0.92px);
26
+ --track-border-width: var(--zn-toggle-track-border-width, 0.92px);
27
+
22
28
  box-sizing: border-box;
23
29
  text-align: left;
24
30
  position: relative;
25
31
  display: inline-flex;
26
- width: 42px;
27
- height: 24px;
32
+ width: var(--track-width);
33
+ height: var(--track-height);
28
34
  flex-shrink: 0;
29
35
  cursor: pointer;
30
- border-radius: 12px;
36
+ border-radius: var(--zn-border-radius-pill);
31
37
  align-items: center;
32
- background-color: rgb(var(--zn-color-tab));
38
+ background-color: var(--zn-toggle-track-background, rgb(var(--zn-color-tab)));
33
39
  // The unchecked track needs an edge of its own. --zn-color-tab sits close to
34
40
  // the surface behind it on dark themes, which left the switch reading as a
35
41
  // free-floating knob with no discoverable control boundary. The checked state
36
42
  // below repaints the border in the accent colour.
37
- border: 0.92px solid rgb(var(--zn-border-color));
43
+ border: var(--track-border-width) solid var(--zn-toggle-track-border-color, rgb(var(--zn-border-color)));
38
44
  margin: var(--zn-toggle-margin);
39
- transition: color .2s ease-in-out, background-color .4s ease-in-out, border-color .2s ease-in-out;
45
+ transition: color .25s ease-out, background-color .25s ease-out, border-color .25s ease-out;
40
46
  }
41
47
 
42
- :host(:focus) .switch__input-wrapper {
43
- outline: rgb(var(--zn-primary)) solid 1px;
48
+ .switch__input-wrapper:has(.switch__input:focus-visible) {
49
+ outline: var(--zn-focus-ring);
50
+ outline-offset: var(--zn-focus-ring-offset);
44
51
  }
45
52
 
46
53
  :host([checked]) .switch__input-wrapper {
@@ -48,7 +55,7 @@
48
55
  border-color: rgb(var(--zn-color-primary));
49
56
 
50
57
  .switch__control {
51
- left: calc(100% - 20.32px - 0.92px);
58
+ translate: calc(var(--track-width) - 2 * var(--track-border-width) - var(--knob-size) - 2 * var(--knob-inset)) -50%;
52
59
  // The knob carries the on/off state, so it takes the on-primary ink: a
53
60
  // white knob on a light accent (neon lime, amber) is invisible.
54
61
  background: rgb(var(--zn-color-on-primary, 255, 255, 255));
@@ -97,14 +104,21 @@
97
104
  pointer-events: none;
98
105
  position: absolute;
99
106
  top: 50%;
100
- left: 0.92px;
101
- width: 20.32px;
102
- height: 20.32px;
107
+ left: var(--knob-inset);
108
+ width: var(--knob-size);
109
+ height: var(--knob-size);
103
110
  border-radius: 50%;
104
- background: #fff;
105
- transform: translateY(-50%);
106
- transition: left .3s ease-in-out, background-color .4s ease-in-out;
111
+ background: var(--zn-toggle-knob-color, #fff);
112
+ box-shadow: var(--zn-toggle-knob-shadow, none);
113
+ // Position lives in `translate` so the squish animation's `scale` doesn't scale the travel distance too.
114
+ translate: 0 -50%;
115
+ // Springy curve: overshoots the far edge slightly, then settles.
116
+ transition: translate .5s linear(0, 0.4 12%, 0.85 25%, 1.06 38%, 1.03 50%, 0.985 64%, 1.005 80%, 1), background-color .25s ease-out;
107
117
  outline: none;
118
+
119
+ @media (prefers-reduced-motion: reduce) {
120
+ transition: background-color .25s ease-out;
121
+ }
108
122
  }
109
123
 
110
124
  .switch__input {
@@ -117,19 +131,9 @@
117
131
 
118
132
  // sizes
119
133
  .switch__wrapper--small .switch__input-wrapper {
120
- height: 20px;
121
- width: 35px;
122
- }
123
-
124
- .switch__wrapper--small .switch__control {
125
- width: 14px;
126
- height: 14px;
127
- }
128
-
129
- :host([checked]) .switch__wrapper--small .switch__input-wrapper {
130
- .switch__control {
131
- left: calc(100% - 14px - 0.92px);
132
- }
134
+ --track-width: var(--zn-toggle-track-width-small, 35px);
135
+ --track-height: var(--zn-toggle-track-height-small, 20px);
136
+ --knob-size: var(--zn-toggle-knob-size-small, 14px);
133
137
  }
134
138
 
135
139
  // Label position
@@ -144,8 +148,11 @@
144
148
  flex-direction: row;
145
149
  }
146
150
 
151
+ // The switch leads and the label follows it, so labels of any length line up. A theme can instead put the label
152
+ // first with the switch at the far edge.
147
153
  .switch__wrapper--label-right label {
148
- flex-direction: row-reverse;
154
+ flex-direction: var(--zn-toggle-side-label-direction, row-reverse);
155
+ justify-content: var(--zn-toggle-side-label-justify, flex-end);
149
156
  }
150
157
 
151
158
  // Support inline label
@@ -19,6 +19,17 @@ describe('<zn-toggle>', () => {
19
19
  expect(label.nextElementSibling).to.equal(description);
20
20
  });
21
21
 
22
+ it('emits zn-change when switched', async () => {
23
+ const el = await fixture<HTMLElement & { updateComplete: Promise<boolean> }>(html` <zn-toggle label="On"></zn-toggle> `);
24
+ let changes = 0;
25
+ el.addEventListener('zn-change', () => changes++);
26
+
27
+ el.shadowRoot!.querySelector<HTMLInputElement>('input')!.click();
28
+ await el.updateComplete;
29
+
30
+ expect(changes).to.equal(1);
31
+ });
32
+
22
33
  describe('form submission', () => {
23
34
  it('should submit the value when checked', async () => {
24
35
  const form = await fixture<HTMLFormElement>(html`
@@ -47,4 +58,10 @@ describe('<zn-toggle>', () => {
47
58
  expect(new FormData(form).get('feature')).to.equal('disabled');
48
59
  });
49
60
  });
61
+
62
+ it('keeps a right-hand label beside the switch', async () => {
63
+ const el = await fixture<HTMLElement>(html`<zn-toggle label="Short" label-position="right"></zn-toggle>`);
64
+ const label = el.shadowRoot!.querySelector('label')!;
65
+ expect(getComputedStyle(label).justifyContent).to.equal('flex-end');
66
+ });
50
67
  });
@@ -62,6 +62,7 @@ export default class ZnTooltip extends ZincElement {
62
62
  }
63
63
 
64
64
  disconnectedCallback() {
65
+ super.disconnectedCallback();
65
66
  this.closeWatcher?.destroy();
66
67
  document.removeEventListener('keydown', this.handleDocumentKeyDown);
67
68
  }
@@ -149,6 +150,8 @@ export default class ZnTooltip extends ZincElement {
149
150
  this.emit('zn-after-show');
150
151
  } else {
151
152
  topLayerManager.unregisterTooltip(this);
153
+ this.closeWatcher?.destroy();
154
+ document.removeEventListener('keydown', this.handleDocumentKeyDown);
152
155
 
153
156
  this.emit('zn-hide');
154
157
  this.popup.active = false;
@@ -7,6 +7,7 @@
7
7
 
8
8
  .tooltip {
9
9
  --arrow-size: 6px;
10
+ --arrow-color: var(--zn-tooltip-background-color, rgb(var(--zn-color-text)));
10
11
  }
11
12
 
12
13
  .tooltip::part(popup),
@@ -36,15 +37,19 @@
36
37
  display: block;
37
38
  width: max-content;
38
39
  max-width: max-content;
39
- border-radius: var(--zn-border-radius);
40
+ font-family: var(--zn-tooltip-font-family, var(--zn-font-sans));
41
+ font-size: var(--zn-tooltip-font-size, var(--zn-text-paragraph-font-size));
42
+ font-weight: var(--zn-tooltip-font-weight, var(--zn-text-paragraph-font-weight));
43
+ line-height: var(--zn-tooltip-line-height, var(--zn-text-paragraph-line-height));
44
+ border-radius: var(--zn-tooltip-border-radius, var(--zn-border-radius));
40
45
  background-color: var(--arrow-color);
46
+ box-shadow: var(--zn-tooltip-shadow, none);
41
47
  text-align: start;
42
48
  white-space: normal;
43
- // The bubble is painted in --arrow-color, which resolves to --zn-color-text,
44
- // so the ink has to be the surface colour rather than a fixed white — on any
45
- // dark theme the text colour is light and white-on-light is unreadable.
46
- color: rgb(var(--zn-color-base, 255, 255, 255));
47
- padding: var(--zn-spacing-x-small) var(--zn-spacing-small);
49
+ // The default bubble is the text colour, so the ink must be the surface
50
+ // colour rather than a fixed white — on a dark theme the text is light.
51
+ color: var(--zn-tooltip-color, rgb(var(--zn-color-base, 255, 255, 255)));
52
+ padding: var(--zn-tooltip-padding, var(--zn-spacing-x-small) var(--zn-spacing-small));
48
53
  pointer-events: none;
49
54
  user-select: none;
50
55
  -webkit-user-select: none;
@@ -75,4 +75,16 @@ describe('<zn-tooltip>', () => {
75
75
  expect(tooltip.open).to.be.false;
76
76
  await dropdown.hide();
77
77
  });
78
+
79
+ it('paints the bubble from the tooltip tokens', async () => {
80
+ const el = await fixture<ZnTooltip>(html`
81
+ <zn-tooltip content="Hi" open
82
+ style="--zn-tooltip-background-color: rgb(1, 2, 3); --zn-tooltip-color: rgb(4, 5, 6)">
83
+ <button>Trigger</button>
84
+ </zn-tooltip>`);
85
+ const body = el.shadowRoot!.querySelector('.tooltip__body')!;
86
+
87
+ expect(getComputedStyle(body).backgroundColor).to.equal('rgb(1, 2, 3)');
88
+ expect(getComputedStyle(body).color).to.equal('rgb(4, 5, 6)');
89
+ });
78
90
  });
@@ -0,0 +1,12 @@
1
+ import ZnTranslationField from './translation-field.component';
2
+
3
+ export * from './translation-field.component';
4
+ export default ZnTranslationField;
5
+
6
+ ZnTranslationField.define('zn-translation-field');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-translation-field': ZnTranslationField;
11
+ }
12
+ }
@@ -0,0 +1,55 @@
1
+ import {classMap} from "lit/directives/class-map.js";
2
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
3
+ import {property} from 'lit/decorators.js';
4
+ import ZincElement from '../../internal/zinc-element';
5
+
6
+ import styles from './translation-field.scss';
7
+
8
+ /**
9
+ * @summary A field's source text beside the control that translates it.
10
+ * @documentation https://zinc.style/components/translation-field
11
+ * @status experimental
12
+ * @since 1.0
13
+ *
14
+ * @slot - The control the translation is written in, such as a `zn-input` with the language code as its prefix.
15
+ * @slot source - The source text, shown read-only.
16
+ * @slot actions - Actions beside the label.
17
+ *
18
+ * @csspart base - The component's base wrapper.
19
+ * @csspart source - The box holding the source.
20
+ */
21
+ export default class ZnTranslationField extends ZincElement {
22
+ static styles: CSSResultGroup = unsafeCSS(styles);
23
+
24
+ @property() label = '';
25
+
26
+ /** The source's language code, shown beside it. */
27
+ @property({attribute: 'source-code'}) sourceCode = '';
28
+
29
+ /** For source text that runs over several lines, such as a message body. */
30
+ @property({type: Boolean, reflect: true}) multiline = false;
31
+
32
+ /** Lines the source up with a control that has a toolbar above it, such as a compact `zn-editor`. */
33
+ @property({type: Boolean, reflect: true}) offset = false;
34
+
35
+ render() {
36
+ return html`
37
+ <div part="base" class="translation-field">
38
+ <div class="translation-field__label">
39
+ <b>${this.label}</b>
40
+ <slot name="actions"></slot>
41
+ </div>
42
+ <div class="translation-field__pair">
43
+ <div part="source" class=${classMap({
44
+ 'translation-field__source': true,
45
+ 'translation-field__source--multiline': this.multiline,
46
+ })}>
47
+ <span class="translation-field__code">${this.sourceCode.toUpperCase()}</span>
48
+ <div class="translation-field__text"><slot name="source"></slot></div>
49
+ </div>
50
+ <div class="translation-field__target"><slot></slot></div>
51
+ </div>
52
+ </div>
53
+ `;
54
+ }
55
+ }
@@ -0,0 +1,101 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ // The source and target codes share a gutter, so the two texts start level
5
+ --translation-field-code-width: 32px;
6
+
7
+ display: block;
8
+ container-type: inline-size;
9
+ }
10
+
11
+ .translation-field {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--zn-spacing-x-small);
15
+ font-size: var(--zn-input-font-size-medium);
16
+ }
17
+
18
+ .translation-field__label {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ gap: calc(var(--zn-spacing-unit, 8px) * 1.5);
23
+ min-height: 26px;
24
+ color: rgb(var(--zn-text));
25
+ }
26
+
27
+ .translation-field__pair {
28
+ display: grid;
29
+ // A zn-translation-fields sets these when it stacks its fields
30
+ grid-template-columns: repeat(var(--translation-field-columns, 2), minmax(0, 1fr));
31
+ gap: calc(var(--zn-spacing-unit, 8px) * 1.5);
32
+
33
+ @container (max-width: 560px) {
34
+ grid-template-columns: minmax(0, 1fr);
35
+ }
36
+ }
37
+
38
+ .translation-field__source {
39
+ box-sizing: border-box;
40
+ display: flex;
41
+ align-items: center;
42
+ gap: calc(var(--zn-spacing-unit, 8px) * 1.5);
43
+ min-width: 0;
44
+ min-height: var(--zn-input-height-medium);
45
+ padding: 0 calc(var(--zn-spacing-unit, 8px) * 1.5);
46
+ border-radius: 8px;
47
+ background-color: var(--zn-input-background-color-disabled);
48
+ color: rgb(var(--zn-color-muted-text));
49
+
50
+ // Level with a compact editor's text: the same padding and line height
51
+ &--multiline {
52
+ align-items: flex-start;
53
+ padding: var(--zn-spacing-x-small) calc(var(--zn-spacing-unit, 8px) * 1.5);
54
+ line-height: 1.5;
55
+ }
56
+ }
57
+
58
+ .translation-field__source {
59
+ align-self: var(--translation-field-source-align, stretch);
60
+ }
61
+
62
+ :host([offset]) .translation-field__source {
63
+ // A compact editor's toolbar and the gap under it
64
+ margin-top: var(--translation-field-source-offset, calc(24px + var(--zn-spacing-unit, 8px) * 1.5));
65
+ }
66
+
67
+ .translation-field__code {
68
+ flex: none;
69
+ width: var(--translation-field-code-width);
70
+ line-height: calc(var(--zn-input-font-size-medium) * 1.5);
71
+ color: rgb(var(--zn-text));
72
+ font-size: 12px;
73
+ font-weight: 700;
74
+ }
75
+
76
+ .translation-field__text {
77
+ flex: 1;
78
+ min-width: 0;
79
+ overflow-wrap: anywhere;
80
+
81
+ // Keeps a plain-text source's line breaks; set on the text alone, as it would inherit into a slotted component
82
+ ::slotted(span) {
83
+ white-space: pre-wrap;
84
+ }
85
+ }
86
+
87
+ .translation-field__target {
88
+ display: flex;
89
+ flex-direction: column;
90
+ min-width: 0;
91
+
92
+ // A code prefix and the text after it start where the source's do
93
+ ::slotted(*) {
94
+ --zn-input-icon-color: rgb(var(--zn-text));
95
+ --zn-input-padding-inline: calc(var(--zn-spacing-unit, 8px) * 1.5);
96
+ --zn-input-prefix-min-width: calc(var(--translation-field-code-width) + var(--zn-spacing-unit, 8px) * 1.5);
97
+ --editor-height: auto;
98
+ // Never shorter than the source beside it
99
+ flex: 1 0 auto;
100
+ }
101
+ }
@@ -0,0 +1,12 @@
1
+ import ZnTranslationFields from './translation-fields.component';
2
+
3
+ export * from './translation-fields.component';
4
+ export default ZnTranslationFields;
5
+
6
+ ZnTranslationFields.define('zn-translation-fields');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-translation-fields': ZnTranslationFields;
11
+ }
12
+ }
@@ -0,0 +1,80 @@
1
+ import {classMap} from "lit/directives/class-map.js";
2
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
3
+ import {property} from 'lit/decorators.js';
4
+ import ZincElement from '../../internal/zinc-element';
5
+
6
+ import styles from './translation-fields.scss';
7
+
8
+ export type TranslationFieldsLayout = 'split' | 'stacked';
9
+
10
+ const LAYOUTS: { layout: TranslationFieldsLayout, label: string, icon: string }[] = [
11
+ {layout: 'split', label: 'Side by side', icon: 'columns-2@lu'},
12
+ {layout: 'stacked', label: 'Stacked', icon: 'rows-2@lu'},
13
+ ];
14
+
15
+ /**
16
+ * @summary Lays out `zn-translation-field`s with their source beside or above the translation, chosen by the viewer.
17
+ * @documentation https://zinc.style/components/translation-fields
18
+ * @status experimental
19
+ * @since 1.0
20
+ *
21
+ * @slot - The `zn-translation-field`s.
22
+ * @slot actions - Actions level with the layout switch.
23
+ *
24
+ * @csspart base - The component's base wrapper.
25
+ */
26
+ export default class ZnTranslationFields extends ZincElement {
27
+ static styles: CSSResultGroup = unsafeCSS(styles);
28
+
29
+ @property({reflect: true}) layout: TranslationFieldsLayout = 'split';
30
+
31
+ /** Remembers the viewer's layout under this key in `localStorage`; leave empty to forget it. */
32
+ @property({attribute: 'store-key'}) storeKey = 'zn-translation-fields-layout';
33
+
34
+ connectedCallback() {
35
+ super.connectedCallback();
36
+ try {
37
+ const stored = this.storeKey ? window.localStorage.getItem(this.storeKey) : null;
38
+ if (stored === 'split' || stored === 'stacked') {
39
+ this.layout = stored;
40
+ }
41
+ } catch {
42
+ // Storage can be blocked; the layout then starts as set
43
+ }
44
+ }
45
+
46
+ private _choose(layout: TranslationFieldsLayout) {
47
+ this.layout = layout;
48
+ try {
49
+ if (this.storeKey) {
50
+ window.localStorage.setItem(this.storeKey, layout);
51
+ }
52
+ } catch {
53
+ // The choice still applies, it just isn't remembered
54
+ }
55
+ this.emit('zn-change');
56
+ }
57
+
58
+ render() {
59
+ return html`
60
+ <div part="base" class="translation-fields">
61
+ <div class="translation-fields__bar">
62
+ <div class="translation-fields__switch" role="group" aria-label="Layout">
63
+ ${LAYOUTS.map(option => html`
64
+ <button type="button"
65
+ class=${classMap({
66
+ 'translation-fields__option': true,
67
+ 'translation-fields__option--active': option.layout === this.layout,
68
+ })}
69
+ aria-pressed=${option.layout === this.layout ? 'true' : 'false'}
70
+ @click=${() => this._choose(option.layout)}>
71
+ <zn-icon src=${option.icon} size="16"></zn-icon>${option.label}
72
+ </button>`)}
73
+ </div>
74
+ <slot name="actions"></slot>
75
+ </div>
76
+ <slot></slot>
77
+ </div>
78
+ `;
79
+ }
80
+ }
@@ -0,0 +1,60 @@
1
+ @use "../../wc";
2
+
3
+ // The fields read these, so the switch changes every field at once
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ :host([layout="stacked"]) {
9
+ --translation-field-columns: 1;
10
+ --translation-field-source-offset: 0px;
11
+ --translation-field-source-align: start;
12
+ }
13
+
14
+ .translation-fields {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: calc(var(--zn-spacing-unit, 8px) * 1.5);
18
+ }
19
+
20
+ .translation-fields__bar {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: space-between;
24
+ gap: calc(var(--zn-spacing-unit, 8px) * 1.5);
25
+ }
26
+
27
+ .translation-fields__switch {
28
+ display: inline-flex;
29
+ gap: 2px;
30
+ padding: 2px;
31
+ border-radius: 8px;
32
+ background: var(--zn-color-neutral-100);
33
+ }
34
+
35
+ .translation-fields__option {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: 6px;
39
+ height: 22px;
40
+ padding: 0 12px;
41
+ border: 0;
42
+ border-radius: 6px;
43
+ background: transparent;
44
+ color: rgb(var(--zn-color-muted-text));
45
+ font: inherit;
46
+ font-size: 12px;
47
+ font-weight: var(--zn-font-weight-semibold);
48
+ cursor: pointer;
49
+
50
+ &--active {
51
+ background: rgb(var(--zn-panel));
52
+ color: rgb(var(--zn-text));
53
+ box-shadow: var(--zn-shadow-small, 0 1px 3px rgba(13, 23, 56, 0.08), 0 1px 2px rgba(13, 23, 56, 0.04));
54
+ }
55
+
56
+ &:focus-visible {
57
+ outline: none;
58
+ box-shadow: 0 0 0 var(--zn-focus-ring-width) var(--zn-input-focus-ring-color);
59
+ }
60
+ }
@@ -0,0 +1,12 @@
1
+ import ZnTranslationGrid from './translation-grid.component';
2
+
3
+ export * from './translation-grid.component';
4
+ export default ZnTranslationGrid;
5
+
6
+ ZnTranslationGrid.define('zn-translation-grid');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-translation-grid': ZnTranslationGrid;
11
+ }
12
+ }