@zeyos/zx 4.3.4 → 5.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 (231) hide show
  1. package/CHANGELOG.md +438 -0
  2. package/README.md +49 -10
  3. package/dist/types/components/activity-item/activity-item.d.ts +351 -0
  4. package/dist/types/components/activity-list/activity-list.d.ts +217 -0
  5. package/dist/types/components/app-sidebar/app-sidebar.d.ts +33 -3
  6. package/dist/types/components/avatar/avatar.d.ts +46 -7
  7. package/dist/types/components/badge/badge.d.ts +21 -1
  8. package/dist/types/components/button/button.d.ts +23 -0
  9. package/dist/types/components/calendar/calendar.d.ts +19 -0
  10. package/dist/types/components/card/card.d.ts +7 -0
  11. package/dist/types/components/card-view/card-view.d.ts +11 -3
  12. package/dist/types/components/card-view/record-card.d.ts +7 -1
  13. package/dist/types/components/chart/chart.d.ts +10 -0
  14. package/dist/types/components/checklist/checklist.d.ts +9 -0
  15. package/dist/types/components/code-editor/code-editor.d.ts +149 -0
  16. package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
  17. package/dist/types/components/context-menu/context-menu.d.ts +18 -2
  18. package/dist/types/components/date-picker/date-picker.d.ts +8 -0
  19. package/dist/types/components/date-picker/time-picker.d.ts +7 -0
  20. package/dist/types/components/datebox/date-range-box.d.ts +5 -1
  21. package/dist/types/components/datebox/datebox.d.ts +7 -2
  22. package/dist/types/components/dialog/dialog.d.ts +75 -6
  23. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  24. package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
  25. package/dist/types/components/field/field.d.ts +24 -2
  26. package/dist/types/components/fieldset/fieldset.d.ts +19 -1
  27. package/dist/types/components/file-item/file-item.d.ts +262 -0
  28. package/dist/types/components/file-list/file-list.d.ts +171 -0
  29. package/dist/types/components/filter/filter.d.ts +91 -36
  30. package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
  31. package/dist/types/components/form/form.d.ts +12 -1
  32. package/dist/types/components/kanban-view/kanban-card.d.ts +146 -0
  33. package/dist/types/components/kanban-view/kanban-view.d.ts +170 -4
  34. package/dist/types/components/launcher/launcher.d.ts +278 -26
  35. package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
  36. package/dist/types/components/menu-button/menu-button.d.ts +37 -42
  37. package/dist/types/components/message/message.d.ts +126 -17
  38. package/dist/types/components/modal/modal.d.ts +61 -2
  39. package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
  40. package/dist/types/components/panel/panel.d.ts +7 -0
  41. package/dist/types/components/search/search.d.ts +7 -0
  42. package/dist/types/components/select/color.d.ts +12 -0
  43. package/dist/types/components/select/glyphs.d.ts +124 -0
  44. package/dist/types/components/select/select.d.ts +15 -3
  45. package/dist/types/components/sort-control/sort-control.d.ts +105 -0
  46. package/dist/types/components/stat-tile/stat-tile.d.ts +288 -0
  47. package/dist/types/components/tabbox/tabbox.d.ts +16 -0
  48. package/dist/types/components/table/table.d.ts +190 -1
  49. package/dist/types/components/table-view/table-view.d.ts +11 -5
  50. package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
  51. package/dist/types/components/timebox/timebox.d.ts +7 -0
  52. package/dist/types/components/tree/tree.d.ts +13 -0
  53. package/dist/types/components/value-list/value-list.d.ts +8 -0
  54. package/dist/types/components/view/record-view.d.ts +96 -5
  55. package/dist/types/core/breakpoint.d.ts +1 -1
  56. package/dist/types/core/icons.d.ts +37 -22
  57. package/dist/types/core/motion.d.ts +59 -0
  58. package/dist/types/core/overlay-host.d.ts +15 -1
  59. package/dist/types/index.d.ts +16 -3
  60. package/dist/types/internal/app-rail.d.ts +10 -0
  61. package/dist/types/internal/menu-items.d.ts +134 -0
  62. package/dist/types/zeyos/connect.d.ts +6 -0
  63. package/dist/types/zeyos/form.d.ts +50 -9
  64. package/dist/types/zeyos/index.d.ts +1 -1
  65. package/dist/types/zeyos/query.d.ts +79 -0
  66. package/dist/types/zeyos/schema.d.ts +24 -1
  67. package/dist/types/zeyos/table.d.ts +100 -14
  68. package/dist/types/zeyos/view.d.ts +10 -0
  69. package/dist/zx-zeyos.esm.js +2206 -489
  70. package/dist/zx-zeyos.esm.min.js +56 -1
  71. package/dist/zx.css +3322 -724
  72. package/dist/zx.esm.js +12244 -5809
  73. package/dist/zx.esm.min.js +58 -3
  74. package/dist/zx.global.js +12246 -5811
  75. package/dist/zx.global.min.js +58 -3
  76. package/dist/zx.min.css +1 -1
  77. package/docs/api.json +1683 -146
  78. package/docs/llms.md +777 -110
  79. package/docs/llms.txt +14 -8
  80. package/package.json +1 -1
  81. package/src/components/account-menu/account-menu.css +35 -10
  82. package/src/components/activity-item/activity-item.css +137 -0
  83. package/src/components/activity-item/activity-item.js +602 -0
  84. package/src/components/activity-list/activity-list.css +99 -0
  85. package/src/components/activity-list/activity-list.js +409 -0
  86. package/src/components/app-icon/app-icon.css +1 -1
  87. package/src/components/app-rail/app-rail.css +191 -22
  88. package/src/components/app-sidebar/app-sidebar.css +349 -24
  89. package/src/components/app-sidebar/app-sidebar.js +86 -11
  90. package/src/components/aurora/aurora.css +5 -3
  91. package/src/components/avatar/avatar.css +32 -7
  92. package/src/components/avatar/avatar.js +72 -8
  93. package/src/components/badge/badge.css +54 -2
  94. package/src/components/badge/badge.js +29 -2
  95. package/src/components/button/button.css +74 -8
  96. package/src/components/button/button.js +44 -1
  97. package/src/components/calendar/calendar.css +46 -46
  98. package/src/components/calendar/calendar.js +33 -3
  99. package/src/components/card/card.css +2 -2
  100. package/src/components/card/card.js +12 -1
  101. package/src/components/card-view/card-view.css +10 -7
  102. package/src/components/card-view/card-view.js +25 -9
  103. package/src/components/card-view/record-card.js +7 -3
  104. package/src/components/chart/chart.css +4 -1
  105. package/src/components/chart/chart.js +12 -0
  106. package/src/components/check-button/check-button.css +10 -2
  107. package/src/components/checklist/checklist.css +9 -2
  108. package/src/components/checklist/checklist.js +11 -5
  109. package/src/components/checklist/field-adapter.js +3 -1
  110. package/src/components/code-editor/code-editor.css +68 -0
  111. package/src/components/code-editor/code-editor.js +306 -0
  112. package/src/components/code-editor/field-adapter.js +34 -0
  113. package/src/components/context-menu/context-menu.css +87 -5
  114. package/src/components/context-menu/context-menu.js +22 -30
  115. package/src/components/copy/copy-button.css +6 -0
  116. package/src/components/copy/copy-input.css +8 -3
  117. package/src/components/data-filter/data-filter.css +5 -4
  118. package/src/components/date-picker/date-picker.css +6 -6
  119. package/src/components/date-picker/date-picker.js +22 -8
  120. package/src/components/date-picker/date-range-picker.css +3 -3
  121. package/src/components/date-picker/month-picker.js +3 -3
  122. package/src/components/date-picker/time-picker.css +1 -1
  123. package/src/components/date-picker/time-picker.js +20 -8
  124. package/src/components/datebox/date-range-box.css +79 -2
  125. package/src/components/datebox/date-range-box.js +13 -2
  126. package/src/components/datebox/datebox.css +79 -2
  127. package/src/components/datebox/datebox.js +13 -2
  128. package/src/components/dialog/dialog.css +26 -0
  129. package/src/components/dialog/dialog.js +174 -70
  130. package/src/components/dropdown/dropdown.css +1 -1
  131. package/src/components/dropdown/dropdown.js +7 -5
  132. package/src/components/empty-state/empty-state.css +2 -2
  133. package/src/components/entity-ref/entity-ref.css +182 -0
  134. package/src/components/entity-ref/entity-ref.js +496 -0
  135. package/src/components/field/field.css +28 -9
  136. package/src/components/field/field.js +68 -26
  137. package/src/components/field-upload/field-upload.css +1 -1
  138. package/src/components/fieldset/fieldset.css +5 -3
  139. package/src/components/fieldset/fieldset.js +28 -5
  140. package/src/components/file-item/file-item.css +88 -0
  141. package/src/components/file-item/file-item.js +505 -0
  142. package/src/components/file-list/file-list.css +51 -0
  143. package/src/components/file-list/file-list.js +320 -0
  144. package/src/components/filter/filter.css +27 -1
  145. package/src/components/filter/filter.js +205 -47
  146. package/src/components/filter-panel/filter-panel.css +104 -0
  147. package/src/components/filter-panel/filter-panel.js +964 -0
  148. package/src/components/finder/finder.css +15 -13
  149. package/src/components/form/form.css +5 -4
  150. package/src/components/form/form.js +11 -2
  151. package/src/components/grid/grid.css +1 -1
  152. package/src/components/groupbox/groupbox.css +1 -1
  153. package/src/components/kanban-view/kanban-card.js +247 -0
  154. package/src/components/kanban-view/kanban-view.css +226 -8
  155. package/src/components/kanban-view/kanban-view.js +255 -12
  156. package/src/components/launcher/launcher.css +107 -25
  157. package/src/components/launcher/launcher.js +557 -63
  158. package/src/components/list-toolbar/list-toolbar.css +194 -0
  159. package/src/components/list-toolbar/list-toolbar.js +851 -0
  160. package/src/components/master-panel/master-panel.css +2 -0
  161. package/src/components/menu-button/menu-button.css +87 -5
  162. package/src/components/menu-button/menu-button.js +86 -46
  163. package/src/components/message/message.css +38 -5
  164. package/src/components/message/message.js +230 -17
  165. package/src/components/modal/modal.css +15 -0
  166. package/src/components/modal/modal.js +159 -3
  167. package/src/components/navigation-bar/navigation-bar.css +95 -11
  168. package/src/components/navigation-bar/navigation-bar.js +171 -4
  169. package/src/components/number-field/field-adapter.js +1 -0
  170. package/src/components/number-field/number-field.css +70 -0
  171. package/src/components/number-field/number-field.js +2 -0
  172. package/src/components/pagination/pagination.css +8 -6
  173. package/src/components/panel/panel.css +1 -1
  174. package/src/components/panel/panel.js +13 -2
  175. package/src/components/rating/rating.css +7 -0
  176. package/src/components/search/search.js +17 -5
  177. package/src/components/select/color.js +22 -0
  178. package/src/components/select/field-adapter.js +6 -1
  179. package/src/components/select/glyphs.js +165 -0
  180. package/src/components/select/select.css +138 -45
  181. package/src/components/select/select.js +86 -47
  182. package/src/components/sheet/sheet.css +11 -8
  183. package/src/components/slider/slider.css +16 -2
  184. package/src/components/slider/slider.js +1 -1
  185. package/src/components/sort-control/sort-control.css +20 -0
  186. package/src/components/sort-control/sort-control.js +140 -0
  187. package/src/components/stat-tile/stat-tile.css +208 -0
  188. package/src/components/stat-tile/stat-tile.js +601 -0
  189. package/src/components/tabbox/tabbox.css +32 -27
  190. package/src/components/tabbox/tabbox.js +17 -2
  191. package/src/components/table/table.css +155 -31
  192. package/src/components/table/table.js +386 -33
  193. package/src/components/table-view/table-view.css +8 -2
  194. package/src/components/table-view/table-view.js +21 -6
  195. package/src/components/tag-picker/tag-picker.css +86 -6
  196. package/src/components/tag-picker/tag-picker.js +25 -8
  197. package/src/components/timebox/timebox.css +22 -2
  198. package/src/components/timebox/timebox.js +18 -5
  199. package/src/components/toggle/toggle.css +12 -1
  200. package/src/components/toolbar/toolbar.js +2 -2
  201. package/src/components/tooltip/tooltip.css +4 -0
  202. package/src/components/tooltip/tooltip.js +10 -3
  203. package/src/components/tree/tree.css +25 -16
  204. package/src/components/tree/tree.js +31 -0
  205. package/src/components/value-list/value-list.css +3 -3
  206. package/src/components/value-list/value-list.js +22 -6
  207. package/src/components/view/record-view.css +5 -0
  208. package/src/components/view/record-view.js +100 -7
  209. package/src/core/breakpoint.js +1 -1
  210. package/src/core/icons.js +259 -57
  211. package/src/core/motion.js +147 -0
  212. package/src/core/overlay-host.js +21 -2
  213. package/src/index.js +30 -3
  214. package/src/internal/app-rail.js +18 -1
  215. package/src/internal/menu-items.js +142 -0
  216. package/src/zeyos/connect.js +6 -2
  217. package/src/zeyos/form.js +67 -27
  218. package/src/zeyos/index.js +1 -1
  219. package/src/zeyos/query.js +153 -0
  220. package/src/zeyos/schema.js +144 -27
  221. package/src/zeyos/table.js +68 -5
  222. package/src/zeyos/view.js +6 -0
  223. package/styles/base.css +56 -0
  224. package/styles/icons.css +11 -1
  225. package/styles/print.css +192 -0
  226. package/styles/tokens/dark.css +113 -37
  227. package/styles/tokens/global.css +121 -27
  228. package/styles/tokens/semantic.css +100 -31
  229. package/styles/tokens/themes.css +7 -6
  230. package/styles/zx.css +11 -1
  231. package/styles/tokens/density.css +0 -9
@@ -2,15 +2,18 @@
2
2
  * Four tab appearances, all square-cornered by default:
3
3
  *
4
4
  * divided (default) flat blocks on a muted track, split by hairline dividers, the active
5
- * block lifted onto the panel surface under an accent rule — the workhorse for a
6
- * record page or a panel that owns its content box.
5
+ * block lifted onto the panel surface it opens — the workhorse for a record page or
6
+ * a panel that owns its content box.
7
7
  * bracket folder tabs that outline and fuse into the panel below, the active tab bridging
8
8
  * the seam — for document-like views where the tabs belong to the sheet.
9
- * segmented a compact group on a muted fill, the active tab raised onto a control surface —
10
- * for switching a view inside a toolbar or card header, where the row reads as one
11
- * control rather than as navigation.
12
- * line a full-width rule with the active tab underlined — for page- and section-level
13
- * navigation, where the row spans the content it switches.
9
+ * segmented a compact framed group, the active tab on the neutral current fill — for switching
10
+ * a view inside a toolbar or card header, where the row reads as one control rather
11
+ * than as navigation.
12
+ * line a full-width rule with the active tab underlined in the text colour — for page- and
13
+ * section-level navigation, where the row spans the content it switches.
14
+ *
15
+ * The active tab is where you are, not something you picked, so no variant marks it with the
16
+ * accent: it takes the text colour and a heavier label, and its own variant's neutral ground.
14
17
  *
15
18
  * `divided` and `bracket` draw the panel box themselves; `line` and `segmented` leave the panel
16
19
  * bare so the surrounding layout supplies the chrome.
@@ -57,7 +60,7 @@
57
60
  color: var(--zx-color-text-muted);
58
61
  font: inherit;
59
62
  font-size: var(--zx-control-font-size);
60
- font-weight: 500;
63
+ font-weight: var(--zx-weight-medium);
61
64
  white-space: nowrap;
62
65
  cursor: pointer;
63
66
  }
@@ -68,6 +71,7 @@
68
71
 
69
72
  .zx-tabbox__tab[aria-selected="true"] {
70
73
  color: var(--zx-color-text);
74
+ font-weight: var(--zx-weight-semibold);
71
75
  }
72
76
 
73
77
  .zx-tabbox__tab[aria-disabled="true"] {
@@ -90,8 +94,6 @@
90
94
 
91
95
  .zx-tabbox[data-variant="divided"] .zx-tabbox__tab {
92
96
  block-size: calc(var(--zx-control-height) + 8px);
93
- /* The top rule is the selected marker; transparent here keeps every block the same height. */
94
- border-block-start: 2px solid transparent;
95
97
  border-inline-end: 1px solid var(--zx-color-border);
96
98
  padding-inline: var(--zx-space-4);
97
99
  }
@@ -104,10 +106,9 @@
104
106
  background: var(--zx-color-bg-hover);
105
107
  }
106
108
 
109
+ /* The active block is lifted onto the panel surface it opens; nothing is docked to its edge. */
107
110
  .zx-tabbox[data-variant="divided"] .zx-tabbox__tab[aria-selected="true"] {
108
- border-block-start-color: var(--zx-color-accent);
109
111
  background: var(--zx-color-bg-surface);
110
- font-weight: 650;
111
112
  }
112
113
 
113
114
  .zx-tabbox[data-variant="divided"] .zx-tabbox__tab:focus-visible {
@@ -141,7 +142,6 @@
141
142
  .zx-tabbox[data-variant="bracket"] .zx-tabbox__tab[aria-selected="true"] {
142
143
  border-color: var(--zx-color-border);
143
144
  background: var(--zx-color-bg-surface);
144
- font-weight: 650;
145
145
  }
146
146
 
147
147
  .zx-tabbox[data-variant="bracket"] .zx-tabbox__tab[aria-selected="true"]::after {
@@ -175,9 +175,10 @@
175
175
  border-block-end-color: var(--zx-color-border-strong);
176
176
  }
177
177
 
178
+ /* The underline is the text colour, not the accent: a tab row is navigation, and the screen's
179
+ one solid accent belongs to its primary action. */
178
180
  .zx-tabbox[data-variant="line"] .zx-tabbox__tab[aria-selected="true"] {
179
- border-block-end-color: var(--zx-color-accent);
180
- font-weight: 600;
181
+ border-block-end-color: var(--zx-color-text);
181
182
  }
182
183
 
183
184
  .zx-tabbox[data-variant="line"] .zx-tabbox__tab:focus-visible {
@@ -188,22 +189,22 @@
188
189
 
189
190
  /* ------------------------------------------------------------- segmented variant -- */
190
191
 
192
+ /* One framed control: a hairline round the group, the segments flat inside it, and the active one
193
+ on the neutral current fill — the same recipe as the view switch in ListToolbar and Calendar. */
191
194
  .zx-tabbox[data-variant="segmented"] .zx-tabbox__tablist {
192
195
  inline-size: fit-content;
193
196
  max-inline-size: 100%;
194
197
  align-items: center;
195
198
  gap: 2px;
196
199
  block-size: var(--zx-control-height);
200
+ border: 1px solid var(--zx-color-border-control);
197
201
  border-radius: var(--zx-tabbox-radius);
198
- background: var(--zx-color-bg-muted);
199
- padding: 3px;
202
+ padding: 2px;
200
203
  }
201
204
 
202
205
  .zx-tabbox[data-variant="segmented"] .zx-tabbox__tab {
203
206
  block-size: 100%;
204
- /* A transparent border keeps the active and inactive boxes the same size. */
205
- border: 1px solid transparent;
206
- /* Nested inside the track's 3px padding, so the inner corner is one step tighter. */
207
+ /* Nested inside the frame's 2px padding, so the inner corner is one step tighter. */
207
208
  border-radius: max(0px, calc(var(--zx-tabbox-radius) - 2px));
208
209
  padding-inline: var(--zx-space-3);
209
210
  font-size: var(--zx-text-sm);
@@ -214,15 +215,12 @@
214
215
  }
215
216
 
216
217
  .zx-tabbox[data-variant="segmented"] .zx-tabbox__tab[aria-selected="true"] {
217
- border-color: var(--zx-color-border-control);
218
- background: var(--zx-color-bg-control);
219
- box-shadow: var(--zx-shadow-2);
218
+ background: var(--zx-color-bg-current);
220
219
  }
221
220
 
222
221
  .zx-tabbox[data-variant="segmented"] .zx-tabbox__tab:focus-visible {
223
222
  z-index: 1;
224
223
  outline: 0;
225
- border-color: var(--zx-color-ring);
226
224
  box-shadow: var(--zx-focus-ring);
227
225
  }
228
226
 
@@ -237,18 +235,25 @@
237
235
 
238
236
  /* ---------------------------------------------------------------- badge & close -- */
239
237
 
238
+ /* A count, not a call to action: a neutral overlay that reads on every variant's ground, in the
239
+ muted text colour, taking the full text colour with its tab. */
240
240
  .zx-tabbox__badge {
241
241
  min-inline-size: 1.25rem;
242
242
  border-radius: var(--zx-radius-full);
243
- background: var(--zx-color-accent);
243
+ background: var(--zx-color-bg-current);
244
244
  padding-inline: var(--zx-space-1);
245
- color: var(--zx-color-on-accent);
245
+ color: var(--zx-color-text-muted);
246
246
  font-size: var(--zx-text-xs);
247
- font-weight: 700;
247
+ font-variant-numeric: tabular-nums;
248
+ font-weight: var(--zx-weight-medium);
248
249
  line-height: 1.25rem;
249
250
  text-align: center;
250
251
  }
251
252
 
253
+ .zx-tabbox__tab[aria-selected="true"] .zx-tabbox__badge {
254
+ color: var(--zx-color-text);
255
+ }
256
+
252
257
  /* Chrome comes from the shared .zx-icon-btn ghost utility; only the box is reset here, because
253
258
  a full control-height square would widen every closable tab. The extra .zx-tabbox raises the
254
259
  specificity to match `.zx-scope .zx-icon-btn` in base.css, which sets the size. */
@@ -37,6 +37,9 @@ const VARIANTS = new Set(['divided', 'bracket', 'line', 'segmented']);
37
37
  * the active tab across a full-width rule; `segmented` renders a compact group that reads as one
38
38
  * control, for a toolbar or card header.
39
39
  * @property {boolean} [keepAlive=true] Keep inactive panel elements mounted.
40
+ * @property {string} [label] Accessible name of the tab list — what the tabs switch between
41
+ * ("Record sections"). A tab list needs one whenever the page has more than one, and screen
42
+ * readers announce it on entry.
40
43
  * @property {(event: CustomEvent<{name: string, previous: string|null}>) => void} [onchange] Change callback.
41
44
  * @property {(event: CustomEvent<{name: string}>) => void} [onclose] Close callback, fired when the
42
45
  * user dismisses a closable tab.
@@ -101,7 +104,8 @@ export class Tabbox extends Component {
101
104
  class: 'zx-tabbox__tablist',
102
105
  ref: 'tablist',
103
106
  role: 'tablist',
104
- ariaOrientation: 'horizontal'
107
+ ariaOrientation: 'horizontal',
108
+ ariaLabel: this.options.label || null
105
109
  });
106
110
  const panels = h('div', {
107
111
  class: 'zx-tabbox__panels',
@@ -179,7 +183,7 @@ export class Tabbox extends Component {
179
183
  children.push(h('span', {
180
184
  class: 'zx-tabbox__close zx-icon-btn',
181
185
  ariaHidden: 'true',
182
- title: 'Close'
186
+ title: this._message('tabbox.close', 'Close')
183
187
  }, icon('x', { size: 14 })));
184
188
  }
185
189
  const tab = /** @type {HTMLButtonElement} */ (h('button', {
@@ -467,6 +471,17 @@ export class Tabbox extends Component {
467
471
  _recordForTab(tab) {
468
472
  return this._tabs.find((record) => record.tab === tab) ?? null;
469
473
  }
474
+
475
+ /**
476
+ * Resolves a message through the host translator, falling back to the built-in English text.
477
+ * @param {string} key Message key.
478
+ * @param {string} fallback English default.
479
+ * @returns {string}
480
+ */
481
+ _message(key, fallback) {
482
+ const message = this.msg(key);
483
+ return message === key ? fallback : message;
484
+ }
470
485
  }
471
486
 
472
487
  /**
@@ -5,7 +5,10 @@
5
5
  .zx-table__column-controls {
6
6
  position: relative;
7
7
  inline-size: max-content;
8
- margin: 0 0 var(--zx-space-2) auto;
8
+ /* `auto` on the inline start, so the controls sit at the trailing edge of the table in either
9
+ direction. The four-value `margin` shorthand this replaces resolved to the physical left. */
10
+ margin-block: 0 var(--zx-space-2);
11
+ margin-inline: auto 0;
9
12
  }
10
13
 
11
14
  .zx-table__reorder-status {
@@ -61,9 +64,9 @@
61
64
  grid-template-columns: minmax(0, 1fr) auto;
62
65
  align-items: center;
63
66
  gap: var(--zx-space-2);
64
- min-block-size: var(--zx-control-height);
67
+ min-block-size: calc(var(--zx-control-height) - 2px);
65
68
  border-radius: var(--zx-radius-sm);
66
- padding-inline: var(--zx-space-2);
69
+ padding: var(--zx-space-1) var(--zx-space-2);
67
70
  }
68
71
 
69
72
  .zx-table__column-option:hover { background: var(--zx-color-overlay-hover); }
@@ -129,16 +132,28 @@
129
132
  }
130
133
  }
131
134
 
135
+ /*
136
+ * The reorder and selection columns are one control height wide, the control centred in the slot.
137
+ * Their cells drop the inline padding: a fixed layout holds the column to exactly that width, and
138
+ * the padding would push the control off its middle. The controls are blocks centred by their
139
+ * margins: inline, they would sit on the text baseline with the descender room left below them, a
140
+ * few pixels above the middle of the row.
141
+ */
132
142
  .zx-table__reorder-column,
133
- .zx-table__reorder-header,
134
- .zx-table__reorder-cell {
143
+ .zx-table__selection-column {
135
144
  inline-size: var(--zx-control-height);
136
- text-align: center;
145
+ }
146
+
147
+ .zx-table :is(.zx-table__reorder-header, .zx-table__reorder-cell,
148
+ .zx-table__selection-header, .zx-table__selection-cell) {
149
+ inline-size: var(--zx-control-height);
150
+ padding-inline: 0;
137
151
  }
138
152
 
139
153
  .zx-table__row-handle {
140
- display: inline-grid;
154
+ display: grid;
141
155
  place-items: center;
156
+ margin-inline: auto;
142
157
  inline-size: 26px;
143
158
  block-size: 26px;
144
159
  min-block-size: 0;
@@ -168,7 +183,9 @@
168
183
  border: 1px solid var(--zx-color-border);
169
184
  border-radius: var(--zx-radius-md);
170
185
  background: var(--zx-color-bg-surface);
171
- scrollbar-gutter: stable;
186
+ /* No reserved gutter: a table that does not scroll would carry a blank strip beside its last
187
+ column wherever scrollbars take up room. One that scrolls gets its scrollbar when it does. */
188
+ scrollbar-gutter: auto;
172
189
  }
173
190
 
174
191
  /* Loading state (Table.setLoading): dim rows and show an indeterminate top progress bar. */
@@ -211,6 +228,8 @@
211
228
  border-spacing: 0;
212
229
  background: var(--zx-color-bg-surface);
213
230
  color: var(--zx-color-text);
231
+ /* Figures line up down a column whatever the cell's alignment. Only digits change width. */
232
+ font-variant-numeric: tabular-nums;
214
233
  }
215
234
 
216
235
  /* Auto layout (intrinsic/px columns): let content set the width and scroll horizontally. */
@@ -224,23 +243,32 @@
224
243
  table-layout: fixed;
225
244
  }
226
245
 
227
- .zx-table__selection-column {
228
- inline-size: var(--zx-control-height);
229
- }
230
-
246
+ /*
247
+ * Rows are separated by the subtle divider, the header from the body by the ordinary one. The
248
+ * header has no band of its own: it sits on the table's surface in the muted text colour at a
249
+ * medium weight, so it labels the columns without competing with the values in them — and stays
250
+ * opaque, which a sticky header has to be.
251
+ */
231
252
  .zx-table th,
232
253
  .zx-table td {
233
- border-block-end: 1px solid var(--zx-table-border-color, var(--zx-color-border));
254
+ border-block-end: 1px solid var(--zx-table-border-color, var(--zx-color-border-subtle));
234
255
  padding: var(--zx-space-2) var(--zx-space-3);
235
256
  text-align: start;
236
257
  vertical-align: middle;
237
258
  }
238
259
 
239
260
  .zx-table th {
240
- background: var(--zx-table-header-bg, var(--zx-color-bg-raised));
261
+ border-block-end-color: var(--zx-table-border-color, var(--zx-color-border));
262
+ background: var(--zx-table-header-bg, var(--zx-color-bg-surface));
241
263
  color: var(--zx-color-text-muted);
242
264
  font-size: var(--zx-text-sm);
243
- font-weight: 650;
265
+ font-weight: var(--zx-weight-medium);
266
+ }
267
+
268
+ /* The column the rows are ordered by says so in its label as well as its arrow. */
269
+ .zx-table th[aria-sort="ascending"],
270
+ .zx-table th[aria-sort="descending"] {
271
+ color: var(--zx-color-text);
244
272
  }
245
273
 
246
274
  .zx-table__scroll[data-sticky-header="true"] th {
@@ -261,9 +289,12 @@
261
289
  text-align: end;
262
290
  }
263
291
 
292
+ /* `left` is the legacy spelling of `start`, exactly as `right` above is the legacy spelling of
293
+ `end`: the alignment follows the writing direction, so a column pinned to `left` sits on the
294
+ right of an RTL table. A caller that means the physical edge sets `text-align` itself. */
264
295
  .zx-table th[data-align="left"],
265
296
  .zx-table td[data-align="left"] {
266
- text-align: left;
297
+ text-align: start;
267
298
  }
268
299
 
269
300
  .zx-table__sort-button {
@@ -278,9 +309,25 @@
278
309
  background: inherit;
279
310
  color: inherit;
280
311
  padding: 0;
312
+ /* The header's type, not a control's: base.css sets buttons in the control size and weight, and
313
+ the browser resets their tracking, so a sortable label would not match its unsortable
314
+ neighbours. */
315
+ font: inherit;
316
+ letter-spacing: inherit;
281
317
  text-align: inherit;
282
318
  }
283
319
 
320
+ /* A sortable figure column keeps its label over the figures: label at the end edge, the direction
321
+ arrow before it. */
322
+ .zx-table th:is([data-align="end"], [data-align="right"]) .zx-table__sort-button {
323
+ flex-direction: row-reverse;
324
+ justify-content: flex-start;
325
+ }
326
+
327
+ .zx-table th[data-align="center"] .zx-table__sort-button {
328
+ justify-content: center;
329
+ }
330
+
284
331
  .zx-table__sort-button:hover {
285
332
  background: var(--zx-table-row-hover-bg, var(--zx-color-bg-hover));
286
333
  color: var(--zx-color-text);
@@ -292,12 +339,12 @@
292
339
 
293
340
  .zx-table th[aria-sort="ascending"] .zx-table__sort-button::after {
294
341
  content: "↑";
295
- color: var(--zx-color-accent);
342
+ color: var(--zx-color-text-muted);
296
343
  }
297
344
 
298
345
  .zx-table th[aria-sort="descending"] .zx-table__sort-button::after {
299
346
  content: "↓";
300
- color: var(--zx-color-accent);
347
+ color: var(--zx-color-text-muted);
301
348
  }
302
349
 
303
350
  .zx-table__body tr:last-child td {
@@ -308,28 +355,65 @@
308
355
  background: var(--zx-color-bg-page);
309
356
  }
310
357
 
358
+ /* Checked rows of a multi-selection are picks and keep the accent tint. The selected row of a
359
+ single-selection table — no checkbox column — is the record you are on, the current row of a
360
+ master–detail list, and takes the neutral current fill instead. */
311
361
  .zx-table__body tr[aria-selected="true"] {
312
362
  background: var(--zx-table-row-selected-bg, var(--zx-color-bg-selected));
313
363
  }
314
364
 
365
+ .zx-table__body tr[aria-selected="true"]:not(:has(> .zx-table__selection-cell)) {
366
+ background: var(--zx-table-row-selected-bg, var(--zx-color-bg-current));
367
+ }
368
+
315
369
  .zx-table__body tr[data-row]:hover {
316
370
  background: var(--zx-color-bg-hover);
317
371
  }
318
372
 
373
+ /* ------------------------------------------------------------------ plain -- */
374
+
375
+ /*
376
+ * `variant: 'plain'` — for a table inside a card or panel that already draws the box: no outer
377
+ * frame, no header band, no zebra, hairline rows. The cells keep their padding, so the hover and
378
+ * selection fills never run up against the text.
379
+ */
380
+ .zx-table[data-variant="plain"] .zx-table__scroll {
381
+ border: 0;
382
+ border-radius: 0;
383
+ background: transparent;
384
+ }
385
+
386
+ .zx-table[data-variant="plain"] .zx-table__table {
387
+ background: transparent;
388
+ }
389
+
390
+ .zx-table[data-variant="plain"] th {
391
+ background: var(--zx-table-header-bg, var(--zx-color-bg-surface));
392
+ border-block-end-color: var(--zx-table-border-color, var(--zx-color-border-subtle));
393
+ }
394
+
395
+ .zx-table[data-variant="plain"] .zx-table__scroll[data-sticky-header="false"] th {
396
+ background: transparent;
397
+ }
398
+
399
+ .zx-table[data-variant="plain"] .zx-table__scroll[data-zebra="true"] .zx-table__body tr:nth-child(even):not([aria-selected="true"]) {
400
+ background: transparent;
401
+ }
402
+
403
+ .zx-table[data-variant="plain"] .zx-table__body tr:last-child td {
404
+ border-block-end: 0;
405
+ }
406
+
407
+
319
408
  .zx-table__checkbox {
409
+ display: block;
320
410
  inline-size: var(--zx-space-4);
321
411
  min-block-size: auto;
322
412
  block-size: var(--zx-space-4);
323
- margin: 0;
413
+ margin: 0 auto;
324
414
  accent-color: var(--zx-color-accent);
325
415
  }
326
416
 
327
- .zx-table__selection-header,
328
- .zx-table__selection-cell {
329
- inline-size: var(--zx-control-height);
330
- text-align: center;
331
- }
332
-
333
417
  .zx-table__empty {
334
418
  padding-block: var(--zx-space-6);
335
419
  color: var(--zx-color-text-muted);
@@ -379,6 +463,49 @@
379
463
  min-inline-size: 0;
380
464
  }
381
465
 
466
+ /* --- Group and section rows (Table rowKinds) ------------------------------------------------ */
467
+
468
+ /*
469
+ * A `span` kind renders one `<th scope="colgroup">` across the whole row, because the cell labels
470
+ * the columns of the records beneath it rather than holding a value of its own. Using `<th>` for
471
+ * that reason means inheriting the header's look and its sticky positioning, neither of which
472
+ * belongs on a body cell — the sticky one would pin every section to the top of the scroller and
473
+ * pile them up there — so both are taken back off here.
474
+ *
475
+ * What is NOT here is a look. No tint, no weight, no rule above it: a billing section is not a
476
+ * kanban swimlane, a default would be the first thing every consumer overrides, and `rowKinds[kind]
477
+ * .class` is where the decision belongs.
478
+ */
479
+ .zx-table .zx-table__body th.zx-table__section-cell {
480
+ position: static;
481
+ z-index: auto;
482
+ background: none;
483
+ color: inherit;
484
+ font-size: inherit;
485
+ font-weight: inherit;
486
+ text-align: start;
487
+ }
488
+
489
+ .zx-table__body tr:last-child > .zx-table__section-cell {
490
+ border-block-end: 0;
491
+ }
492
+
493
+ /*
494
+ * Stacked, a spanning row is its heading and nothing else. The labelled-line treatment is what the
495
+ * rest of the card is made of, and applying it here produces a heading followed by a column of
496
+ * empty labelled blanks — the exact artefact hosts are writing stylesheet workarounds for.
497
+ */
498
+ .zx-table[data-stacked] .zx-table__body > tr[data-span] > * {
499
+ display: block;
500
+ inline-size: auto;
501
+ padding-inline: 0;
502
+ text-align: start;
503
+ }
504
+
505
+ .zx-table[data-stacked] .zx-table__body > tr[data-span] > *::before {
506
+ content: none;
507
+ }
508
+
382
509
  /* --- Inline editing (Table editMode) -------------------------------------------------------- */
383
510
 
384
511
  /* Reserve a control-sized content box in every body cell as soon as the table is editable, so
@@ -534,12 +661,9 @@
534
661
  content: none;
535
662
  }
536
663
 
537
- .zx-table[data-stacked] .zx-table__selection-cell {
538
- justify-content: flex-start;
539
- }
540
-
541
- .zx-table[data-stacked] .zx-table__reorder-cell {
542
- justify-content: flex-start;
664
+ /* A card's checkbox and handle lead their line, where the auto margins would centre them. */
665
+ .zx-table[data-stacked] :is(.zx-table__checkbox, .zx-table__row-handle) {
666
+ margin-inline: 0;
543
667
  }
544
668
 
545
669