@kubex/zinc 1.1.185 → 2.0.1

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 +10319 -2666
  6. package/dist/vscode.html-custom-data.json +1012 -57
  7. package/dist/web-types.json +2097 -145
  8. package/dist/zn.d.ts +2294 -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 +136 -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 +632 -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
@@ -26,6 +26,7 @@
26
26
  .input--standard {
27
27
  background-color: var(--zn-input-background-color);
28
28
  border: solid var(--zn-input-border-width) var(--zn-input-border-color);
29
+ box-shadow: var(--zn-input-shadow, none);
29
30
  }
30
31
 
31
32
  .input--standard:hover:not(.input--disabled, .input--filled) {
@@ -55,6 +56,15 @@
55
56
  color: var(--zn-input-color-focus);
56
57
  }
57
58
 
59
+ /* Invalid, once the user has interacted */
60
+ :host([data-user-invalid]) .input--standard:not(.input--disabled) {
61
+ border-color: var(--zn-input-border-color-invalid);
62
+ }
63
+
64
+ :host([data-user-invalid]) .input--standard.input--focused:not(.input--disabled) {
65
+ box-shadow: 0 0 0 var(--zn-focus-ring-width) var(--zn-input-focus-ring-color-invalid);
66
+ }
67
+
58
68
  .input--standard.input--disabled {
59
69
  background-color: var(--zn-input-background-color-disabled);
60
70
  border-color: var(--zn-input-border-color-disabled);
@@ -90,12 +100,13 @@
90
100
  cursor: inherit;
91
101
  -webkit-appearance: none;
92
102
  line-height: var(--zn-input-line-height);
103
+ text-overflow: ellipsis;
93
104
  }
94
105
 
95
- /* Color input text should use monospace font */
96
106
  input[type='text'].input__control[data-color-input] {
97
- font-family: var(--zn-font-mono, 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', monospace);
98
- font-size: 0.9em;
107
+ font-family: var(--zn-font-family-mono);
108
+ font-size: 12px;
109
+ font-variant-numeric: tabular-nums;
99
110
  }
100
111
 
101
112
  .input__control::-webkit-search-decoration,
@@ -128,6 +139,11 @@ input[type='text'].input__control[data-color-input] {
128
139
  outline: none;
129
140
  }
130
141
 
142
+ .input__prefix {
143
+ // Holds the text at the same start for prefixes of differing widths, such as language codes
144
+ min-width: var(--zn-input-prefix-min-width, 0);
145
+ }
146
+
131
147
  .input__prefix,
132
148
  .input__suffix {
133
149
  display: inline-flex;
@@ -165,7 +181,7 @@ input[type='text'].input__control[data-color-input] {
165
181
 
166
182
  .input--x-small .input__control {
167
183
  height: calc(var(--zn-input-height-x-small) - var(--zn-input-border-width) * 2);
168
- padding: 0 var(--zn-input-spacing-small) 0 var(--zn-spacing-small);
184
+ padding: 0 var(--zn-input-spacing-small) 0 var(--zn-input-padding-inline, var(--zn-spacing-small));
169
185
  }
170
186
 
171
187
  .input--x-small .input__clear,
@@ -199,7 +215,7 @@ input[type='text'].input__control[data-color-input] {
199
215
 
200
216
  .input--small .input__control {
201
217
  height: calc(var(--zn-input-height-small) - var(--zn-input-border-width) * 2);
202
- padding: 0 var(--zn-input-spacing-small) 0 var(--zn-spacing-small);
218
+ padding: 0 var(--zn-input-spacing-small) 0 var(--zn-input-padding-inline, var(--zn-spacing-small));
203
219
  }
204
220
 
205
221
  .input--small .input__clear,
@@ -233,7 +249,7 @@ input[type='text'].input__control[data-color-input] {
233
249
 
234
250
  .input--medium .input__control {
235
251
  height: calc(var(--zn-input-height-medium) - var(--zn-input-border-width) * 2);
236
- padding: 0 var(--zn-input-spacing-small) 0 var(--zn-spacing-small);
252
+ padding: 0 var(--zn-input-spacing-small) 0 var(--zn-input-padding-inline, var(--zn-spacing-small));
237
253
  }
238
254
 
239
255
  .input--medium .input__clear,
@@ -281,7 +297,7 @@ input[type='text'].input__control[data-color-input] {
281
297
 
282
298
  .input--large .input__control {
283
299
  height: calc(var(--zn-input-height-large) - var(--zn-input-border-width) * 2);
284
- padding: 0 var(--zn-input-spacing-medium) 0 var(--zn-spacing-small);
300
+ padding: 0 var(--zn-input-spacing-medium) 0 var(--zn-input-padding-inline, var(--zn-spacing-small));
285
301
  }
286
302
 
287
303
  .input--large .input__clear,
@@ -326,7 +342,7 @@ input[type='text'].input__control[data-color-input] {
326
342
  */
327
343
 
328
344
  .input__clear:not(.input__clear--visible) {
329
- visibility: hidden;
345
+ display: none;
330
346
  }
331
347
 
332
348
  .input__clear,
@@ -357,8 +373,12 @@ input[type='text'].input__control[data-color-input] {
357
373
  outline: none;
358
374
  }
359
375
 
376
+ .input__password-toggle:focus-visible {
377
+ outline: var(--zn-focus-ring);
378
+ }
379
+
360
380
  .input--empty .input__clear {
361
- visibility: hidden;
381
+ display: none;
362
382
  }
363
383
 
364
384
  /* Don't show the browser's password toggle in Edge */
@@ -382,47 +402,63 @@ input[type='date']::-webkit-calendar-picker-indicator {
382
402
  background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="14" width="12.25" viewBox="0 0 448 512"><path fill="%236d7176" d="M128 0c13.3 0 24 10.7 24 24V64H296V24c0-13.3 10.7-24 24-24s24 10.7 24 24V64h40c35.3 0 64 28.7 64 64v16 48V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V192 144 128C0 92.7 28.7 64 64 64h40V24c0-13.3 10.7-24 24-24zM400 192H48V448c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V192zM112 256h96c8.8 0 16 7.2 16 16v96c0 8.8-7.2 16-16 16H112c-8.8 0-16-7.2-16-16V272c0-8.8 7.2-16 16-16z"/></svg>');
383
403
  }
384
404
 
385
- /* Color input styling — the preview fills the trailing edge of the field */
405
+ /* Colour inputs lead with a swatch that opens the colour panel, divided from the value */
386
406
  .input__color-swatch {
387
- display: inline-flex;
407
+ display: grid;
408
+ place-content: center;
409
+ flex: 0 0 auto;
388
410
  align-self: stretch;
411
+ padding: 0;
412
+ margin: 0;
413
+ background: transparent;
389
414
  border: none;
390
- border-inline-start: solid var(--zn-input-border-width) var(--zn-input-border-color);
391
- border-radius: 0;
392
- background-color: var(--zn-color-neutral-0);
415
+ border-inline-end: solid var(--zn-input-border-width) var(--zn-input-border-color);
393
416
  cursor: pointer;
394
- overflow: hidden;
395
- position: relative;
396
- flex-shrink: 0;
397
- margin: 0;
398
417
 
399
- &:hover .input__color-swatch-inner {
400
- filter: brightness(0.95);
418
+ &:focus-visible {
419
+ outline: none;
420
+ box-shadow: inset 0 0 0 2px var(--zn-focus-ring-color);
421
+ }
422
+
423
+ &:disabled {
424
+ cursor: not-allowed;
401
425
  }
402
426
  }
403
427
 
404
428
  .input__color-swatch-inner {
405
- width: 100%;
406
- height: 100%;
407
- background-color: var(--color-value, #000000);
408
- transition: var(--zn-transition-fast) filter;
429
+ width: 18px;
430
+ height: 18px;
431
+ border-radius: 4px;
432
+ box-shadow: inset 0 0 0 1px var(--zn-input-border-color);
409
433
  }
410
434
 
411
- /* Size adjustments for color inputs — .input clips the trailing corners */
412
435
  .input--x-small .input__color-swatch {
413
- width: calc(var(--zn-input-height-x-small) * 1.2);
436
+ width: var(--zn-input-height-x-small);
414
437
  }
415
438
 
416
439
  .input--small .input__color-swatch {
417
- width: calc(var(--zn-input-height-small) * 1.2);
440
+ width: var(--zn-input-height-small);
418
441
  }
419
442
 
420
443
  .input--medium .input__color-swatch {
421
- width: calc(var(--zn-input-height-medium) * 1.2);
444
+ width: var(--zn-input-height-medium);
422
445
  }
423
446
 
424
447
  .input--large .input__color-swatch {
425
- width: calc(var(--zn-input-height-large) * 1.2);
448
+ width: var(--zn-input-height-large);
449
+ }
450
+
451
+ .input--standard.input--color-invalid:not(.input--disabled) {
452
+ border-color: var(--zn-input-border-color-invalid);
453
+ }
454
+
455
+ .input--color-invalid .input__control,
456
+ .input--color-invalid:hover .input__control {
457
+ color: var(--zn-color-danger-fg);
458
+ }
459
+
460
+ .input__color-popup::part(popup) {
461
+ z-index: var(--zn-z-index-dropdown);
426
462
  }
427
463
 
428
464
  /* Range inputs render as a bare track, with the value shown in the context note above */
@@ -540,17 +576,3 @@ input[type='date']::-webkit-calendar-picker-indicator {
540
576
  .input--range .input__control:focus-visible::-moz-range-thumb {
541
577
  box-shadow: 0 0 0 var(--zn-focus-ring-width) var(--zn-input-focus-ring-color);
542
578
  }
543
-
544
- /* Hide the native color input but keep it functional */
545
- .input__color-picker {
546
- position: absolute;
547
- opacity: 0;
548
- width: 0;
549
- height: 0;
550
- padding: 0;
551
- margin: 0;
552
- pointer-events: none;
553
- border: none;
554
- visibility: hidden;
555
- }
556
-
@@ -34,7 +34,7 @@ describe('<zn-input>', () => {
34
34
  });
35
35
 
36
36
  describe('Escape key', () => {
37
- it('blurs the inner input and stops propagation when focused', async () => {
37
+ it('keeps focus and swallows only the first Escape', async () => {
38
38
  const wrapper = await fixture<HTMLDivElement>(html`
39
39
  <div>
40
40
  <zn-input></zn-input>
@@ -52,16 +52,20 @@ describe('<zn-input>', () => {
52
52
  await el.updateComplete;
53
53
  expect(el.shadowRoot!.activeElement).to.equal(el.input);
54
54
 
55
- el.input.dispatchEvent(new KeyboardEvent('keydown', {
55
+ const pressEscape = () => el.input.dispatchEvent(new KeyboardEvent('keydown', {
56
56
  key: 'Escape',
57
57
  bubbles: true,
58
58
  composed: true,
59
59
  cancelable: true
60
60
  }));
61
- await el.updateComplete;
62
61
 
63
- expect(el.shadowRoot!.activeElement, 'inner input should be blurred').to.not.equal(el.input);
62
+ pressEscape();
63
+ await el.updateComplete;
64
+ expect(el.shadowRoot!.activeElement, 'inner input should keep focus').to.equal(el.input);
64
65
  expect(wrapperEscapes, 'wrapper should not see Escape on press 1').to.equal(0);
66
+
67
+ pressEscape();
68
+ expect(wrapperEscapes, 'wrapper should see Escape on press 2').to.equal(1);
65
69
  });
66
70
  });
67
71
 
@@ -241,6 +245,68 @@ describe('<zn-input>', () => {
241
245
  });
242
246
  });
243
247
 
248
+ describe('type="color"', () => {
249
+ const typeInto = async (el: ZnInput, text: string) => {
250
+ const control = el.shadowRoot!.querySelector<HTMLInputElement>('.input__control')!;
251
+ control.focus();
252
+ control.value = text;
253
+ control.dispatchEvent(new Event('input', {bubbles: true, composed: true}));
254
+ control.dispatchEvent(new Event('change'));
255
+ control.blur();
256
+ await el.updateComplete;
257
+ await el.updateComplete;
258
+ };
259
+
260
+ it('writes the starting value in color-format', async () => {
261
+ const el = await fixture<ZnInput>(html`<zn-input type="color" color-format="rgb" value="#7557F5"></zn-input>`);
262
+ await el.updateComplete;
263
+
264
+ expect(el.value).to.equal('rgb(117, 87, 245)');
265
+ });
266
+
267
+ it('switches to the format that was typed and keeps a tidy value as written', async () => {
268
+ const el = await fixture<ZnInput>(html`<zn-input type="color" value="#085EFD"></zn-input>`);
269
+
270
+ await typeInto(el, 'oklch(70% 0.15 250)');
271
+
272
+ expect(el.colorFormat).to.equal('oklch');
273
+ expect(el.value).to.equal('oklch(70% 0.15 250)');
274
+ });
275
+
276
+ it('writes a name out in the current format', async () => {
277
+ const el = await fixture<ZnInput>(html`<zn-input type="color" value="#085EFD"></zn-input>`);
278
+
279
+ await typeInto(el, 'rebeccapurple');
280
+
281
+ expect(el.value).to.equal('#663399');
282
+ });
283
+
284
+ it('marks text that is not a colour as invalid', async () => {
285
+ const el = await fixture<ZnInput>(html`<zn-input type="color" value="#085EFD"></zn-input>`);
286
+
287
+ await typeInto(el, 'not a colour');
288
+
289
+ const control = el.shadowRoot!.querySelector('.input__control')!;
290
+ expect(control.getAttribute('aria-invalid')).to.equal('true');
291
+ expect(el.shadowRoot!.querySelector('[part="base"]')!.classList.contains('input--color-invalid')).to.be.true;
292
+ });
293
+
294
+ it('opens the colour panel from the swatch and closes it on Escape', async () => {
295
+ const el = await fixture<ZnInput>(html`<zn-input type="color" value="#085EFD"></zn-input>`);
296
+ const swatch = el.shadowRoot!.querySelector<HTMLButtonElement>('.input__color-swatch')!;
297
+
298
+ swatch.click();
299
+ await el.updateComplete;
300
+ expect(swatch.getAttribute('aria-expanded')).to.equal('true');
301
+ expect(el.shadowRoot!.querySelector('zn-color-picker')).to.exist;
302
+
303
+ document.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
304
+ await el.updateComplete;
305
+ expect(swatch.getAttribute('aria-expanded')).to.equal('false');
306
+ expect(el.shadowRoot!.querySelector('zn-color-picker')).to.not.exist;
307
+ });
308
+ });
309
+
244
310
  describe('slash menu', () => {
245
311
  function slashMenuOf(el: ZnInput) {
246
312
  return el.shadowRoot!.querySelector<ZnSlashMenu>('zn-slash-menu');
@@ -351,4 +417,20 @@ describe('<zn-input>', () => {
351
417
  expect(el.shadowRoot!.activeElement, 'the field should keep focus').to.equal(el.input);
352
418
  });
353
419
  });
420
+
421
+ it('paints the invalid border once the user has submitted', async () => {
422
+ const form = await fixture<HTMLFormElement>(html`
423
+ <form @submit=${(e: Event) => e.preventDefault()}>
424
+ <zn-input required style="--zn-input-border-color-invalid: rgb(1, 2, 3)"></zn-input>
425
+ </form>`);
426
+ const el = form.querySelector<ZnInput>('zn-input')!;
427
+ const base = el.shadowRoot!.querySelector('.input')!;
428
+ expect(getComputedStyle(base).borderColor).to.not.equal('rgb(1, 2, 3)');
429
+
430
+ form.requestSubmit();
431
+ await el.updateComplete;
432
+
433
+ expect(el.hasAttribute('data-user-invalid')).to.be.true;
434
+ expect(getComputedStyle(base).borderColor).to.equal('rgb(1, 2, 3)');
435
+ });
354
436
  });
@@ -37,6 +37,15 @@ export default class ZnItem extends ZincElement {
37
37
 
38
38
  @property({type: Boolean}) stacked: boolean;
39
39
 
40
+ /** A fact in a grid of headline attributes: a small muted caption above the value, without padding. */
41
+ @property({type: Boolean, reflect: true}) fact: boolean;
42
+
43
+ /** A row in a key–value list: a small muted caption beside a right-aligned value, on a compact row. */
44
+ @property({attribute: 'key-value', type: Boolean, reflect: true}) keyValue: boolean;
45
+
46
+ /** Shows the value in the monospace font, for identifiers and codes. */
47
+ @property({type: Boolean, reflect: true}) mono: boolean;
48
+
40
49
  @property({reflect: true}) size: 'small' | 'medium' | 'large' = 'medium';
41
50
 
42
51
  @property({attribute: 'edit-on-hover', type: Boolean}) editOnHover: boolean;
@@ -117,6 +126,9 @@ export default class ZnItem extends ZincElement {
117
126
  'item': true,
118
127
  'item--with-content': this._hasContent(),
119
128
  'item--stacked': this.stacked,
129
+ 'item--fact': this.fact,
130
+ 'item--key-value': this.keyValue,
131
+ 'item--mono': this.mono,
120
132
  'item--edit-on-hover': this.editOnHover,
121
133
  'item--inline': this.inline,
122
134
  'item--grid': this.grid,
@@ -7,6 +7,11 @@
7
7
  --zn-item-label-max-width: 450px;
8
8
  }
9
9
 
10
+ // Inset by the panel padding on the host, so a divided list's dividers stop at the card's content edge
11
+ :host([key-value]) {
12
+ margin-inline: var(--zn-panel-padding, var(--zn-spacing-medium));
13
+ }
14
+
10
15
  .item {
11
16
  display: flex;
12
17
  flex-direction: row;
@@ -81,7 +86,7 @@
81
86
  width: 100%;
82
87
 
83
88
  ::slotted(a) {
84
- color: rgb(var(--zn-primary)) !important;
89
+ color: var(--zn-color-primary-fg, rgb(var(--zn-primary))) !important;
85
90
  }
86
91
 
87
92
  ::slotted(zn-icon) {
@@ -156,13 +161,48 @@
156
161
  gap: var(--zn-spacing-2x-small);
157
162
  }
158
163
 
164
+ &--fact {
165
+ flex-direction: column;
166
+ align-items: baseline;
167
+ gap: var(--zn-spacing-3x-small);
168
+ padding: 0;
169
+ min-height: 0;
170
+
171
+ .item__headings {
172
+ width: auto;
173
+ max-width: none;
174
+ }
175
+
176
+ .item__caption {
177
+ font-size: var(--zn-font-size-small);
178
+ font-weight: 400;
179
+ line-height: var(--zn-line-height-dense);
180
+ color: var(--zn-text-color-muted);
181
+ }
182
+
183
+ .item__content {
184
+ max-width: 100%;
185
+ font-size: var(--zn-font-size-small);
186
+ font-weight: var(--zn-font-weight-medium);
187
+ line-height: var(--zn-line-height-dense);
188
+ overflow-wrap: anywhere;
189
+ }
190
+ }
191
+
192
+
159
193
  &--edit-on-hover {
160
194
  ::slotted(zn-inline-edit::part('actions')) {
161
195
  display: none;
162
196
  }
163
197
 
198
+ // Visually hidden rather than display: none, so keyboard users can still tab to them
164
199
  .item__actions {
165
- display: none;
200
+ display: flex;
201
+ position: absolute;
202
+ width: 1px;
203
+ height: 1px;
204
+ overflow: hidden;
205
+ clip-path: inset(50%);
166
206
  }
167
207
 
168
208
  &:hover {
@@ -171,7 +211,11 @@
171
211
  }
172
212
 
173
213
  .item__actions {
174
- display: flex;
214
+ position: static;
215
+ width: auto;
216
+ height: auto;
217
+ overflow: visible;
218
+ clip-path: none;
175
219
  }
176
220
  }
177
221
  }
@@ -209,6 +253,52 @@
209
253
  }
210
254
  }
211
255
 
256
+ // Declared after --with-content so its caption width wins at equal specificity
257
+ &--key-value {
258
+ padding-inline: 0;
259
+ align-items: center;
260
+ gap: var(--zn-spacing-x-small);
261
+ min-height: 2.4rem;
262
+ padding-block: var(--zn-spacing-3x-small);
263
+
264
+ // Stays a row on a narrow container: the caption is short and the value wraps instead
265
+ @include wc.container-query(null, sm) {
266
+ flex-direction: row;
267
+ align-items: center;
268
+ }
269
+
270
+ .item__headings {
271
+ width: 38%;
272
+ min-width: 6rem;
273
+ max-width: 38%;
274
+ }
275
+
276
+ .item__caption {
277
+ font-size: var(--zn-font-size-small);
278
+ font-weight: 400;
279
+ line-height: var(--zn-line-height-dense);
280
+ color: var(--zn-text-color-muted);
281
+ }
282
+
283
+ .item__content {
284
+ align-items: center;
285
+ gap: var(--zn-spacing-2x-small);
286
+ min-width: 0;
287
+ font-size: var(--zn-font-size-small);
288
+ }
289
+
290
+ .item__content-inner {
291
+ min-width: 0;
292
+ text-align: right;
293
+ overflow-wrap: anywhere;
294
+ }
295
+ }
296
+
297
+ &--mono .item__content-inner {
298
+ font-family: var(--zn-font-mono);
299
+ font-size: 0.92em;
300
+ }
301
+
212
302
  &--no-padding {
213
303
  padding: 0 !important;
214
304
  }
@@ -218,3 +308,12 @@
218
308
  grid-template-columns: 1fr 1fr;
219
309
  }
220
310
  }
311
+
312
+ // Slotted actions take focus in the light DOM, which only the host's :focus-within sees
313
+ :host(:focus-within) .item--edit-on-hover .item__actions {
314
+ position: static;
315
+ width: auto;
316
+ height: auto;
317
+ overflow: visible;
318
+ clip-path: none;
319
+ }
@@ -15,4 +15,27 @@ describe('<zn-item>', () => {
15
15
  expect(content).to.exist;
16
16
  expect(getComputedStyle(content!).textAlign).to.equal('right');
17
17
  });
18
+
19
+ it('renders a fact with a muted caption above its value', async () => {
20
+ const el = await fixture<HTMLElement>(html`<zn-item fact caption="Sender">noreply@example.com</zn-item>`);
21
+ await (el as unknown as {updateComplete: Promise<unknown>}).updateComplete;
22
+ const base = el.shadowRoot!.querySelector('.item')!;
23
+
24
+ expect(base.classList.contains('item--fact')).to.be.true;
25
+ expect(getComputedStyle(base).flexDirection).to.equal('column');
26
+ expect(getComputedStyle(el.shadowRoot!.querySelector('.item__caption')!).fontWeight).to.equal('400');
27
+ });
28
+
29
+ it('renders a key-value row with a muted caption beside a right-aligned value', async () => {
30
+ const el = await fixture<HTMLElement>(html`<zn-item key-value mono caption="Charge ID">fVeWtIUlss82t3RvFxD</zn-item>`);
31
+ await (el as unknown as {updateComplete: Promise<unknown>}).updateComplete;
32
+ const base = el.shadowRoot!.querySelector('.item')!;
33
+ const content = el.shadowRoot!.querySelector('.item__content-inner')!;
34
+
35
+ expect(base.classList.contains('item--key-value')).to.be.true;
36
+ expect(getComputedStyle(base).flexDirection).to.equal('row');
37
+ expect(getComputedStyle(el.shadowRoot!.querySelector('.item__caption')!).fontWeight).to.equal('400');
38
+ expect(getComputedStyle(content).textAlign).to.equal('right');
39
+ expect(base.classList.contains('item--mono')).to.be.true;
40
+ });
18
41
  });
@@ -31,7 +31,7 @@ export default class ZnKey extends ZincElement {
31
31
  const chipType = this.active ? this.color : 'transparent';
32
32
 
33
33
  return html`
34
- <div class="key" @click="${this._handleClick}">
34
+ <button type="button" class="key" aria-pressed="${this.active}" @click="${this._handleClick}">
35
35
  <zn-chip
36
36
  .icon="${this.icon}"
37
37
  .iconSize="${this.iconSize}"
@@ -41,7 +41,7 @@ export default class ZnKey extends ZincElement {
41
41
  <div class="key__description">
42
42
  <slot></slot>
43
43
  </div>
44
- </div>
44
+ </button>
45
45
  `;
46
46
  }
47
47
  }
@@ -5,6 +5,12 @@
5
5
  }
6
6
 
7
7
  .key {
8
+ width: 100%;
9
+ padding: 0;
10
+ border: 0;
11
+ background: none;
12
+ font: inherit;
13
+ color: inherit;
8
14
  cursor: pointer;
9
15
  display: flex;
10
16
  flex-direction: row;
@@ -19,6 +25,11 @@
19
25
  line-height: var(--zn-line-height-normal);
20
26
  user-select: none;
21
27
  }
28
+
29
+ &:focus-visible {
30
+ outline: var(--zn-focus-ring);
31
+ border-radius: var(--zn-border-radius-small);
32
+ }
22
33
  }
23
34
 
24
35
  :host([active]) .key__label {
@@ -0,0 +1,12 @@
1
+ import ZnKeyValue from './key-value.component';
2
+
3
+ export * from './key-value.component';
4
+ export default ZnKeyValue;
5
+
6
+ ZnKeyValue.define('zn-key-value');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-key-value': ZnKeyValue;
11
+ }
12
+ }