@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
@@ -1,6 +1,6 @@
1
1
  .zx-calendar {
2
2
  --zx-calendar-time-axis: 4.75rem;
3
- --zx-calendar-slot-height: 24px;
3
+ --zx-calendar-slot-height: var(--zx-space-6);
4
4
  --zx-calendar-event-color: var(--zx-color-accent);
5
5
  position: relative;
6
6
  container-type: inline-size;
@@ -40,13 +40,15 @@
40
40
 
41
41
  .zx-calendar__navigation { justify-self: start; gap: var(--zx-space-1); }
42
42
  .zx-calendar__commands { justify-self: end; gap: var(--zx-space-3); }
43
+ /* The view switch is one framed control with the current view on the neutral current fill — the
44
+ same recipe as ListToolbar's view switch and the segmented Tabbox. */
43
45
  .zx-calendar__views {
44
46
  block-size: var(--zx-control-height);
45
47
  gap: 2px;
46
48
  overflow-x: auto;
47
- border-radius: 0;
48
- background: var(--zx-color-bg-muted);
49
- padding: 3px;
49
+ border: 1px solid var(--zx-color-border-control);
50
+ border-radius: var(--zx-control-radius);
51
+ padding: 2px;
50
52
  }
51
53
 
52
54
  .zx-calendar__toolbar-button,
@@ -75,32 +77,32 @@
75
77
  block-size: 100%;
76
78
  min-block-size: 0;
77
79
  border-color: transparent;
78
- border-radius: 0;
80
+ border-radius: max(0px, calc(var(--zx-control-radius) - 2px));
79
81
  background: transparent;
82
+ color: var(--zx-color-text-muted);
80
83
  padding-inline: var(--zx-space-3);
84
+ font-weight: var(--zx-weight-medium);
81
85
  }
86
+ .zx-calendar__view-button:hover:not(:disabled) { color: var(--zx-color-text); }
82
87
  .zx-calendar__view-button[aria-pressed="true"] {
83
- position: relative;
84
- z-index: 1;
85
- border-color: var(--zx-color-border-control);
86
- background: var(--zx-color-bg-control);
87
- box-shadow: var(--zx-shadow-2);
88
+ background: var(--zx-color-bg-current);
88
89
  color: var(--zx-color-text);
90
+ font-weight: var(--zx-weight-semibold);
89
91
  }
90
92
 
91
93
  .zx-calendar__new {
92
94
  gap: var(--zx-space-2);
93
- border-color: var(--zx-color-accent);
95
+ border-color: var(--zx-color-accent-solid);
94
96
  border-radius: var(--zx-control-radius);
95
- background: var(--zx-color-accent);
96
- color: var(--zx-color-on-accent);
97
+ background: var(--zx-color-accent-solid);
98
+ color: var(--zx-color-on-accent-solid);
97
99
  padding-inline: var(--zx-space-3);
98
- font-weight: 650;
100
+ font-weight: var(--zx-weight-medium);
99
101
  }
100
102
 
101
103
  .zx-calendar__toolbar-button:hover:not(:disabled),
102
104
  .zx-calendar__view-button:hover:not(:disabled):not([aria-pressed="true"]) { background: var(--zx-color-bg-hover); }
103
- .zx-calendar__new:hover:not(:disabled) { background: var(--zx-color-accent-hover); }
105
+ .zx-calendar__new:hover:not(:disabled) { border-color: var(--zx-color-accent-solid-hover); background: var(--zx-color-accent-solid-hover); }
104
106
  .zx-calendar button:disabled { cursor: default; opacity: .55; }
105
107
 
106
108
  .zx-calendar__toolbar-button:focus-visible,
@@ -126,7 +128,8 @@
126
128
  overflow: hidden;
127
129
  color: var(--zx-color-text);
128
130
  font-size: var(--zx-text-lg);
129
- font-weight: 700;
131
+ font-weight: var(--zx-weight-semibold);
132
+ letter-spacing: var(--zx-tracking-title);
130
133
  line-height: 1.25;
131
134
  text-align: center;
132
135
  text-overflow: ellipsis;
@@ -148,10 +151,10 @@
148
151
  }
149
152
 
150
153
  .zx-calendar__time-header,
151
- .zx-calendar__all-day { border-block-end: 1px solid var(--zx-color-border); }
154
+ .zx-calendar__all-day { border-block-end: 1px solid var(--zx-color-border-subtle); }
152
155
  .zx-calendar__time-corner,
153
156
  .zx-calendar__all-day-label {
154
- border-inline-end: 1px solid var(--zx-color-border);
157
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
155
158
  color: var(--zx-color-text-muted);
156
159
  }
157
160
 
@@ -167,7 +170,7 @@
167
170
  place-content: center;
168
171
  border: 0;
169
172
  border-radius: 0;
170
- border-inline-end: 1px solid var(--zx-color-border);
173
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
171
174
  background: var(--zx-color-bg-surface);
172
175
  color: var(--zx-color-text);
173
176
  font: inherit;
@@ -176,8 +179,8 @@
176
179
 
177
180
  .zx-calendar__day-heading:last-child { border-inline-end: 0; }
178
181
  .zx-calendar__day-heading:hover:not(:disabled) { background: var(--zx-color-bg-hover); }
179
- .zx-calendar__day-heading[aria-current="date"] .zx-calendar__day-number { color: var(--zx-color-accent); font-weight: 750; }
180
- .zx-calendar__day-weekday { color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); text-transform: uppercase; letter-spacing: .04em; }
182
+ .zx-calendar__day-heading[aria-current="date"] .zx-calendar__day-number { color: var(--zx-color-accent); font-weight: 650; }
183
+ .zx-calendar__day-weekday { color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); font-weight: var(--zx-weight-medium); }
181
184
  .zx-calendar__day-number { font-size: var(--zx-text-sm); }
182
185
 
183
186
  .zx-calendar__all-day { min-block-size: calc(var(--zx-control-height) + var(--zx-space-2)); }
@@ -198,7 +201,7 @@
198
201
  overflow: hidden;
199
202
  }
200
203
 
201
- .zx-calendar__all-day-cell { border-inline-end: 1px solid var(--zx-color-border); }
204
+ .zx-calendar__all-day-cell { border-inline-end: 1px solid var(--zx-color-border-subtle); }
202
205
  .zx-calendar__all-day-cell:last-of-type { border-inline-end: 0; }
203
206
 
204
207
  .zx-calendar__time-scroller {
@@ -212,7 +215,7 @@
212
215
  .zx-calendar__time-axis {
213
216
  position: relative;
214
217
  z-index: 2;
215
- border-inline-end: 1px solid var(--zx-color-border);
218
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
216
219
  background: var(--zx-color-bg-surface);
217
220
  }
218
221
 
@@ -247,8 +250,8 @@
247
250
  min-inline-size: 0;
248
251
  border: 0;
249
252
  border-radius: 0;
250
- border-block-start: 1px solid var(--zx-color-border);
251
- border-inline-end: 1px solid var(--zx-color-border);
253
+ border-block-start: 1px solid var(--zx-color-border-subtle);
254
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
252
255
  background: var(--zx-color-bg-surface);
253
256
  padding: 0;
254
257
  cursor: crosshair;
@@ -321,7 +324,7 @@
321
324
  }
322
325
 
323
326
  .zx-calendar__event-time { overflow: hidden; color: var(--zx-color-text-muted); text-overflow: ellipsis; white-space: nowrap; }
324
- .zx-calendar__event-title { overflow: hidden; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; }
327
+ .zx-calendar__event-title { overflow: hidden; font-weight: var(--zx-weight-semibold); text-overflow: ellipsis; white-space: nowrap; }
325
328
  .zx-calendar__event-location { overflow: hidden; color: var(--zx-color-text-muted); text-overflow: ellipsis; white-space: nowrap; }
326
329
 
327
330
  .zx-calendar__event-resize {
@@ -378,7 +381,8 @@
378
381
  inset-inline-start: var(--zx-space-1);
379
382
  color: var(--zx-color-danger);
380
383
  font-size: var(--zx-text-xs);
381
- font-weight: 700;
384
+ font-weight: var(--zx-weight-semibold);
385
+ font-variant-numeric: tabular-nums;
382
386
  transform: translateY(-100%);
383
387
  }
384
388
 
@@ -386,19 +390,19 @@
386
390
  .zx-calendar__agenda-day {
387
391
  display: grid;
388
392
  grid-template-columns: minmax(10rem, 22%) minmax(0, 1fr);
389
- border-block-end: 1px solid var(--zx-color-border);
393
+ border-block-end: 1px solid var(--zx-color-border-subtle);
390
394
  }
391
395
  .zx-calendar__agenda-heading {
392
396
  align-self: stretch;
393
397
  appearance: none;
394
398
  border: 0;
395
- border-inline-end: 1px solid var(--zx-color-border);
399
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
396
400
  border-radius: 0;
397
401
  background: var(--zx-color-bg-muted);
398
402
  color: var(--zx-color-text);
399
403
  padding: var(--zx-space-3);
400
404
  font: inherit;
401
- font-weight: 700;
405
+ font-weight: var(--zx-weight-semibold);
402
406
  text-align: start;
403
407
  cursor: pointer;
404
408
  }
@@ -408,7 +412,7 @@
408
412
  min-inline-size: 0;
409
413
  }
410
414
  .zx-calendar__agenda-empty { margin: 0; color: var(--zx-color-text-muted); padding: var(--zx-space-3); }
411
- .zx-calendar__agenda-events > .zx-calendar__event { border-block-end: 1px solid var(--zx-color-border); }
415
+ .zx-calendar__agenda-events > .zx-calendar__event { border-block-end: 1px solid var(--zx-color-border-subtle); }
412
416
  .zx-calendar__agenda-events > .zx-calendar__event:last-child { border-block-end: 0; }
413
417
  .zx-calendar__event[data-variant="agenda"] .zx-calendar__event-action {
414
418
  grid-template-columns: minmax(6rem, 18%) minmax(0, 1fr);
@@ -440,7 +444,7 @@
440
444
  grid-template-columns: auto minmax(0, 1fr);
441
445
  }
442
446
 
443
- .zx-calendar__month-weekdays { border-block-end: 1px solid var(--zx-color-border); }
447
+ .zx-calendar__month-weekdays { border-block-end: 1px solid var(--zx-color-border-subtle); }
444
448
  .zx-calendar__month-week-gutter,
445
449
  .zx-calendar__month-week-number { inline-size: 2.5rem; }
446
450
  .zx-calendar__month-weekdays:not(:has(.zx-calendar__month-week-gutter)) { grid-template-columns: repeat(7, minmax(0, 1fr)); }
@@ -449,17 +453,15 @@
449
453
  padding: var(--zx-space-2);
450
454
  color: var(--zx-color-text-muted);
451
455
  font-size: var(--zx-text-xs);
452
- font-weight: 650;
456
+ font-weight: var(--zx-weight-medium);
453
457
  text-align: center;
454
- text-transform: uppercase;
455
- letter-spacing: .04em;
456
458
  }
457
- .zx-calendar__month-week { min-block-size: 7.5rem; border-block-end: 1px solid var(--zx-color-border); }
459
+ .zx-calendar__month-week { min-block-size: 7.5rem; border-block-end: 1px solid var(--zx-color-border-subtle); }
458
460
  .zx-calendar__month-week-number {
459
461
  grid-row: 1;
460
462
  appearance: none;
461
463
  border: 0;
462
- border-inline-end: 1px solid var(--zx-color-border);
464
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
463
465
  border-radius: 0;
464
466
  background: var(--zx-color-bg-muted);
465
467
  color: var(--zx-color-text-muted);
@@ -488,7 +490,7 @@
488
490
  justify-content: flex-end;
489
491
  min-block-size: var(--zx-control-height);
490
492
  border: 0;
491
- border-inline-end: 1px solid var(--zx-color-border);
493
+ border-inline-end: 1px solid var(--zx-color-border-subtle);
492
494
  border-radius: 0;
493
495
  background: var(--zx-color-bg-surface);
494
496
  color: var(--zx-color-text);
@@ -501,7 +503,7 @@
501
503
  .zx-calendar__month-day[data-other-month="true"] { color: var(--zx-color-text-muted); background: var(--zx-color-bg-muted); }
502
504
  .zx-calendar__month-day[aria-current="date"] {
503
505
  color: var(--zx-color-accent);
504
- font-weight: 750;
506
+ font-weight: 650;
505
507
  }
506
508
  .zx-calendar__month-day:hover:not(:disabled) { background: var(--zx-color-bg-hover); }
507
509
  .zx-calendar__month-events {
@@ -545,8 +547,8 @@
545
547
  padding: var(--zx-space-5);
546
548
  }
547
549
  .zx-calendar__year-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; align-content: start; }
548
- .zx-calendar__year-heading { grid-column: 1 / -1; margin: 0 0 var(--zx-space-2); font-size: var(--zx-text-md); }
549
- .zx-calendar__year-weekday { color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); font-weight: 650; text-align: center; }
550
+ .zx-calendar__year-heading { grid-column: 1 / -1; margin: 0 0 var(--zx-space-2); font-size: var(--zx-text-md); font-weight: var(--zx-weight-semibold); }
551
+ .zx-calendar__year-weekday { color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); font-weight: var(--zx-weight-medium); text-align: center; }
550
552
  .zx-calendar__year-day,
551
553
  .zx-calendar__year-blank { aspect-ratio: 1; }
552
554
  .zx-calendar__year-day {
@@ -562,7 +564,7 @@
562
564
  }
563
565
  .zx-calendar__year-day[data-activity="1"] { background: color-mix(in srgb, var(--zx-color-accent) 10%, var(--zx-color-bg-surface)); }
564
566
  .zx-calendar__year-day[data-activity="2"] { background: color-mix(in srgb, var(--zx-color-accent) 20%, var(--zx-color-bg-surface)); }
565
- .zx-calendar__year-day[data-activity="3"] { background: color-mix(in srgb, var(--zx-color-accent) 32%, var(--zx-color-bg-surface)); font-weight: 700; }
567
+ .zx-calendar__year-day[data-activity="3"] { background: color-mix(in srgb, var(--zx-color-accent) 32%, var(--zx-color-bg-surface)); font-weight: var(--zx-weight-semibold); }
566
568
  .zx-calendar__year-day[aria-current="date"] { outline: 2px solid var(--zx-color-accent); outline-offset: -2px; }
567
569
  .zx-calendar__year-day:hover:not(:disabled) { background: var(--zx-color-bg-hover); }
568
570
 
@@ -574,7 +576,7 @@
574
576
  place-items: center;
575
577
  background: color-mix(in srgb, var(--zx-color-bg-surface) 82%, transparent);
576
578
  color: var(--zx-color-text);
577
- font-weight: 650;
579
+ font-weight: var(--zx-weight-medium);
578
580
  }
579
581
  .zx-calendar__loading[hidden] { display: none; }
580
582
  .zx-calendar[data-state="loading"] .zx-calendar__body { opacity: .55; }
@@ -606,15 +608,13 @@
606
608
  inset-block-start: 0;
607
609
  z-index: 3;
608
610
  border-inline-end: 0;
609
- border-block-end: 1px solid var(--zx-color-border);
611
+ border-block-end: 1px solid var(--zx-color-border-subtle);
610
612
  }
611
613
  .zx-calendar__agenda-events { grid-column: 1; }
612
614
  .zx-calendar__event[data-variant="agenda"] .zx-calendar__event-action { grid-template-columns: 5.5rem minmax(0, 1fr); }
613
615
  .zx-calendar__year { grid-template-columns: 1fr; padding: var(--zx-space-3); }
614
616
  }
615
617
 
616
- [data-zx-density="compact"] .zx-calendar { --zx-calendar-slot-height: 20px; }
617
-
618
618
  @media (prefers-reduced-motion: no-preference) {
619
619
  .zx-calendar__event { transition: transform var(--zx-dur-fast) var(--zx-ease), opacity var(--zx-dur-fast) var(--zx-ease); }
620
620
  .zx-calendar__toolbar-button,
@@ -1,6 +1,7 @@
1
1
  import { Component } from '../../core/component.js';
2
2
  import { h } from '../../core/dom.js';
3
3
  import { icon } from '../../core/icons.js';
4
+ import { printf } from '../../core/i18n.js';
4
5
  import {
5
6
  CALENDAR_VIEWS, addCalendarDays, calendarDayDifference, calendarDayKey,
6
7
  calendarEventIntersects, calendarEventSpansDays, calendarPageDate, calendarRange,
@@ -189,7 +190,7 @@ export class Calendar extends Component {
189
190
  ref: 'views',
190
191
  class: 'zx-calendar__views',
191
192
  role: 'group',
192
- ariaLabel: 'Calendar view'
193
+ ariaLabel: this._message('calendar.viewSwitch', 'Calendar view')
193
194
  }, this._views.map((view) => h('button', {
194
195
  type: 'button',
195
196
  class: 'zx-calendar__view-button',
@@ -643,7 +644,7 @@ export class Calendar extends Component {
643
644
  eventCount: String(count)
644
645
  },
645
646
  ariaCurrent: sameCalendarDay(day, this._now()) ? 'date' : null,
646
- ariaLabel: `${this._format(day, { dateStyle: 'full' })}, ${count} ${count === 1 ? 'event' : 'events'}`,
647
+ ariaLabel: this._dayCountLabel(day, count),
647
648
  disabled: this.options.disabled
648
649
  }, this._format(day, { day: 'numeric' })));
649
650
  }
@@ -708,7 +709,7 @@ export class Calendar extends Component {
708
709
  activity: String(Math.min(3, count))
709
710
  },
710
711
  ariaCurrent: sameCalendarDay(day, this._now()) ? 'date' : null,
711
- ariaLabel: `${this._format(day, { dateStyle: 'full' })}, ${count} ${count === 1 ? 'event' : 'events'}`,
712
+ ariaLabel: this._dayCountLabel(day, count),
712
713
  disabled: this.options.disabled
713
714
  }, String(day.getDate())));
714
715
  }
@@ -1473,6 +1474,35 @@ export class Calendar extends Component {
1473
1474
  if (!this._destroyed) this.refs.status.textContent = message;
1474
1475
  });
1475
1476
  }
1477
+
1478
+ /**
1479
+ * Names a month or year cell by its date and how many events it holds. Singular and plural are
1480
+ * separate keys because a language that inflects the noun cannot reach it from one template.
1481
+ * @param {Date} day Day the cell stands for.
1482
+ * @param {number} count Events on that day.
1483
+ * @returns {string}
1484
+ */
1485
+ _dayCountLabel(day, count) {
1486
+ const date = this._format(day, { dateStyle: 'full' });
1487
+ return count === 1
1488
+ ? this._message('calendar.dayEvent', '%1, %2 event', date, count)
1489
+ : this._message('calendar.dayEvents', '%1, %2 events', date, count);
1490
+ }
1491
+
1492
+ /**
1493
+ * Resolves a message through the host translator, falling back to the built-in English text.
1494
+ *
1495
+ * Distinct from `msg()`: the built-in `msg` option answers the calendar's own vocabulary, so a
1496
+ * dotted key falls past it to the host translator, which is what these strings never had.
1497
+ * @param {string} key Message key.
1498
+ * @param {string} fallback Built-in text, with `%1`-style placeholders.
1499
+ * @param {...unknown} args Interpolation values.
1500
+ * @returns {string}
1501
+ */
1502
+ _message(key, fallback, ...args) {
1503
+ const message = this.msg(key, ...args);
1504
+ return message === key ? printf(fallback, args) : message;
1505
+ }
1476
1506
  }
1477
1507
 
1478
1508
  /** @param {unknown} value @returns {CalendarView[]} */
@@ -107,9 +107,9 @@
107
107
  min-inline-size: 0;
108
108
  margin: 0;
109
109
  font-size: var(--zx-text-lg);
110
- font-weight: 700;
110
+ font-weight: 650;
111
111
  line-height: 1.3;
112
- letter-spacing: -0.012em;
112
+ letter-spacing: var(--zx-tracking-title);
113
113
  }
114
114
 
115
115
  .zx-card__primary,
@@ -86,7 +86,7 @@ export class Card extends Component {
86
86
  ref: 'actions',
87
87
  class: 'zx-card__actions',
88
88
  role: 'group',
89
- ariaLabel: 'Card actions',
89
+ ariaLabel: this._message('card.actions', 'Card actions'),
90
90
  hidden: true
91
91
  });
92
92
  const content = h('div', { ref: 'content', class: 'zx-card__content', hidden: true });
@@ -225,6 +225,17 @@ export class Card extends Component {
225
225
  if (!this.refs.header) return;
226
226
  this.refs.header.hidden = this._title === '' && this.refs.actions.childElementCount === 0;
227
227
  }
228
+
229
+ /**
230
+ * Resolves a message through the host translator, falling back to the built-in English text.
231
+ * @param {string} key Message key.
232
+ * @param {string} fallback English default.
233
+ * @returns {string}
234
+ */
235
+ _message(key, fallback) {
236
+ const message = this.msg(key);
237
+ return message === key ? fallback : message;
238
+ }
228
239
  }
229
240
 
230
241
  /** @param {Element} host @param {CardContent} content @param {string} label */
@@ -107,9 +107,11 @@
107
107
  box-shadow: var(--zx-focus-ring);
108
108
  }
109
109
 
110
+ /* A selected card is a pick, so it keeps the accent — as a tint over the card and its outline,
111
+ not a doubled frame. */
110
112
  .zx-record-card[data-selected="true"] {
111
113
  border-color: var(--zx-color-accent);
112
- box-shadow: inset 0 0 0 1px var(--zx-color-accent);
114
+ background: var(--zx-color-bg-selected);
113
115
  }
114
116
 
115
117
  .zx-record-card__preview {
@@ -224,7 +226,7 @@
224
226
  margin: 0;
225
227
  overflow-wrap: anywhere;
226
228
  font-size: var(--zx-text-lg);
227
- font-weight: 700;
229
+ font-weight: 650;
228
230
  line-height: 1.35;
229
231
  }
230
232
 
@@ -317,7 +319,7 @@
317
319
  overflow: hidden;
318
320
  color: var(--zx-color-text-muted);
319
321
  font-size: var(--zx-text-xs);
320
- font-weight: 600;
322
+ font-weight: var(--zx-weight-medium);
321
323
  line-height: 1.35;
322
324
  text-overflow: ellipsis;
323
325
  white-space: nowrap;
@@ -475,7 +477,7 @@
475
477
 
476
478
  .zx-card-view .zx-record-card__heading {
477
479
  font-size: var(--zx-text-md);
478
- font-weight: 600;
480
+ font-weight: var(--zx-weight-semibold);
479
481
  line-height: 1.3;
480
482
  }
481
483
 
@@ -521,8 +523,8 @@
521
523
  align-items: center;
522
524
  gap: var(--zx-space-1);
523
525
  max-inline-size: 100%;
524
- border: 1px solid var(--zx-color-border);
525
- border-radius: var(--zx-radius-full);
526
+ /* A tinted label/value pair, not a box inside the card's box: the fill alone separates it. */
527
+ border-radius: var(--zx-radius-sm);
526
528
  background: var(--zx-color-bg-muted);
527
529
  padding: calc(var(--zx-space-1) / 2) var(--zx-space-2);
528
530
  }
@@ -530,7 +532,7 @@
530
532
  .zx-card-view .zx-record-card__label {
531
533
  flex: none;
532
534
  font-size: var(--zx-text-xs);
533
- font-weight: 500;
535
+ font-weight: var(--zx-weight-medium);
534
536
  line-height: 1.2;
535
537
  }
536
538
 
@@ -589,3 +591,4 @@
589
591
  min-block-size: 44px;
590
592
  }
591
593
  }
594
+ .zx-card-view .zx-record-card[data-selection-trigger="card"] { cursor: pointer; }
@@ -1,6 +1,6 @@
1
1
  // @ts-check
2
2
  import { h, restoreTarget, snapshotTarget } from '../../core/dom.js';
3
- import { RecordView, readViewField } from '../view/record-view.js';
3
+ import { normalizeViewFieldControls, RecordView, readViewField } from '../view/record-view.js';
4
4
  import {
5
5
  createRecordCard, resolveRecordActions
6
6
  } from './record-card.js';
@@ -21,10 +21,13 @@ import {
21
21
  * @property {import('../view/record-view.js').ViewSort|null} [sort=null] Initial shared sort.
22
22
  * @property {'local'|'server'} [sortMode='local'] Local sorting or event-only server sorting.
23
23
  * @property {false|'single'|'multi'} [selectable=false] Record selection behavior.
24
+ * @property {'checkbox'|'card'} [selectionTrigger='checkbox'] Select through a checkbox or the non-interactive card surface.
24
25
  * @property {unknown[]} [selection=[]] Initially selected record ids.
25
26
  * @property {string[]} [fieldOrder=[]] Preferred shared field order.
26
27
  * @property {string[]} [hiddenFields=[]] Initially hidden metadata fields.
27
- * @property {boolean} [fieldControls=true] Whether to expose shared field controls.
28
+ * @property {boolean|import('../view/record-view.js').ViewFieldControlsConfig} [fieldControls=true]
29
+ * Whether to expose shared field controls. `true` renders the chooser in the card toolbar and
30
+ * `false` omits it; an object customises its `label` and mounts it into `target`.
28
31
  * @property {string|Node|(()=>string|Node)|null} [emptyText=null] Empty-result content.
29
32
  * @property {RecordCardValueSource} [titleField=null] Title field id or explicit resolver.
30
33
  * @property {RecordCardValueSource} [subtitleField=null] Subtitle field id or explicit resolver.
@@ -79,6 +82,7 @@ export class CardView extends RecordView {
79
82
  /** @type {Readonly<CardViewOptions & RecordViewOptions>} */
80
83
  static defaults = {
81
84
  ...RecordView.defaults,
85
+ selectionTrigger: 'checkbox',
82
86
  titleField: null,
83
87
  subtitleField: null,
84
88
  preview: undefined,
@@ -124,10 +128,12 @@ export class CardView extends RecordView {
124
128
  this._initRecordView(root);
125
129
  root.setAttribute('aria-label', String(options.label || 'Card view'));
126
130
  const sort = h('label', { ref: 'sortWrap', class: 'zx-card-view__sort' },
127
- h('span', { class: 'zx-card-view__sort-label' }, 'Sort'),
128
- h('select', { ref: 'sort', ariaLabel: 'Sort cards' }));
131
+ h('span', { class: 'zx-card-view__sort-label' }, this._message('cardView.sort', 'Sort')),
132
+ h('select', { ref: 'sort', ariaLabel: this._message('cardView.sortCards', 'Sort cards') }));
129
133
  const toolbar = h('div', { class: 'zx-record-view__toolbar zx-card-view__toolbar' }, sort);
130
- if (this.options.fieldControls) toolbar.append(this._createViewFieldControls('Fields'));
134
+ if (normalizeViewFieldControls(this.options.fieldControls).enabled) {
135
+ this._mountViewFieldControls(toolbar);
136
+ }
131
137
  const content = h('div', { ref: 'content', class: 'zx-card-view__content' });
132
138
  root.replaceChildren(toolbar, content);
133
139
  this.listen(this.refs.sort, 'change', () => this._changeCardSort());
@@ -140,6 +146,7 @@ export class CardView extends RecordView {
140
146
  this._renderCards();
141
147
  return root;
142
148
  } catch (error) {
149
+ this._removeViewFieldControls();
143
150
  if (!created) restoreTarget(root, this._cardOriginal);
144
151
  throw error;
145
152
  }
@@ -212,16 +219,18 @@ export class CardView extends RecordView {
212
219
  if (!this.refs?.sort || !this.refs?.sortWrap) return;
213
220
  const select = /** @type {HTMLSelectElement} */ (this.refs.sort);
214
221
  const sort = this.getSort();
215
- const options = [h('option', { value: '', selected: sort === null }, 'Unsorted')];
222
+ const options = [h('option', {
223
+ value: '', selected: sort === null
224
+ }, this._message('cardView.unsorted', 'Unsorted'))];
216
225
  for (const field of this.getFields().filter((candidate) => candidate.sortable)) {
217
226
  options.push(h('option', {
218
227
  selected: sort?.id === field.id && sort.dir === 'asc',
219
228
  dataset: { sortId: field.id, sortDir: 'asc' }
220
- }, `${field.label} (ascending)`));
229
+ }, this._message('cardView.sortAscending', '%1 (ascending)', field.label)));
221
230
  options.push(h('option', {
222
231
  selected: sort?.id === field.id && sort.dir === 'desc',
223
232
  dataset: { sortId: field.id, sortDir: 'desc' }
224
- }, `${field.label} (descending)`));
233
+ }, this._message('cardView.sortDescending', '%1 (descending)', field.label)));
225
234
  }
226
235
  select.replaceChildren(...options);
227
236
  /** @type {HTMLElement} */ (this.refs.sortWrap).hidden = options.length === 1;
@@ -286,6 +295,7 @@ export class CardView extends RecordView {
286
295
  link: options.link,
287
296
  actions: options.actions,
288
297
  selectable: this.options.selectable,
298
+ selectionTrigger: options.selectionTrigger,
289
299
  selected: this._isViewSelected(id),
290
300
  variant: this._cardVariant,
291
301
  headingLevel: this._cardHeadingLevel
@@ -355,6 +365,11 @@ export class CardView extends RecordView {
355
365
  return;
356
366
  }
357
367
  if (isInteractiveWithin(target, card) || hasCardTextSelection(card)) return;
368
+ if (this.options.selectable && this._cardOptions().selectionTrigger === 'card') {
369
+ this.toggleSelection(id, { range: event.shiftKey });
370
+ card.focus({ preventScroll: true });
371
+ return;
372
+ }
358
373
  this._activateCard(record, id, index, event);
359
374
  if (this.options.selectable === 'single') this.toggleSelection(id, { selected: true });
360
375
  }
@@ -381,7 +396,8 @@ export class CardView extends RecordView {
381
396
  const id = this._viewRecordId(record);
382
397
  if (event.key === 'Enter') {
383
398
  event.preventDefault();
384
- this._activateCard(record, id, index, event);
399
+ if (this.options.selectable && this._cardOptions().selectionTrigger === 'card') this.toggleSelection(id);
400
+ else this._activateCard(record, id, index, event);
385
401
  } else if (event.key === ' ' && this.options.selectable) {
386
402
  event.preventDefault();
387
403
  this.toggleSelection(id);
@@ -62,6 +62,7 @@ import { readViewField, renderViewField } from '../view/record-view.js';
62
62
  * @property {RecordCardLink|((record:ViewRecord,index:number)=>RecordCardLink)} [link]
63
63
  * @property {RecordCardAction[]|((record:ViewRecord,index:number)=>RecordCardAction[])} [actions=[]]
64
64
  * @property {false|'single'|'multi'} [selectable=false] Selection presentation.
65
+ * @property {'checkbox'|'card'} [selectionTrigger='checkbox'] Selection affordance for owning views.
65
66
  * @property {boolean} [selected=false] Current selection state.
66
67
  * @property {'outlined'|'raised'|'filled'} [variant='outlined'] Surface treatment.
67
68
  * @property {1|2|3|4|5|6} [headingLevel=3] Card title heading level.
@@ -84,7 +85,8 @@ import { readViewField, renderViewField } from '../view/record-view.js';
84
85
  *
85
86
  * The returned `<li>` belongs in a semantic `<ul>`/`<ol>`. When selectable its global
86
87
  * `aria-description` announces selection without applying the unsupported `aria-selected` state
87
- * to a listitem; multi-selection also adds a native checkbox. It deliberately remains a listitem
88
+ * to a listitem; multi-selection adds a native checkbox unless the owner opts into card-surface
89
+ * selection. It deliberately remains a listitem
88
90
  * rather than becoming an ARIA option because cards may contain native links and buttons, which
89
91
  * the listbox pattern does not permit inside an option. Preview images are paired with a stable
90
92
  * fallback. The owning component listens for image `error` and marks the fallback.
@@ -129,7 +131,7 @@ export function createRecordCard(record, index, options = {}) {
129
131
  const titleRow = titlePrefix
130
132
  ? h('div', { class: 'zx-record-card__title-row' }, titlePrefix, heading)
131
133
  : heading;
132
- const selection = selectable === 'multi' ? h('label', {
134
+ const selection = selectable === 'multi' && options.selectionTrigger !== 'card' ? h('label', {
133
135
  class: 'zx-record-card__selection'
134
136
  }, h('input', {
135
137
  type: 'checkbox',
@@ -154,10 +156,12 @@ export function createRecordCard(record, index, options = {}) {
154
156
  tabindex: 0,
155
157
  ariaDescription: selectable ? selected ? 'Selected' : 'Not selected' : undefined,
156
158
  ariaLabelledby: headingId,
159
+ ariaKeyshortcuts: selectable && options.selectionTrigger === 'card' ? 'Space Enter' : undefined,
157
160
  dataset: {
158
161
  recordIndex: String(index),
159
162
  variant: normalizeVariant(options.variant),
160
- selected: String(selected)
163
+ selected: String(selected),
164
+ selectionTrigger: selectable && options.selectionTrigger === 'card' ? 'card' : 'checkbox'
161
165
  }
162
166
  }, preview ? createPreview(preview) : null, body));
163
167
  return card;
@@ -8,6 +8,9 @@
8
8
  .zx-chart__viewport {
9
9
  position: relative;
10
10
  inline-size: 100%;
11
+ /* The automatic minimum width would carry the 220px floor through the aspect ratio (587px at
12
+ 16 / 6) and push the canvas out of a narrow card; narrow, the chart grows taller instead. */
13
+ min-inline-size: 0;
11
14
  min-block-size: 220px;
12
15
  aspect-ratio: var(--zx-chart-aspect-ratio, 16 / 9);
13
16
  }
@@ -54,7 +57,7 @@
54
57
  border-collapse: collapse;
55
58
  }
56
59
 
57
- .zx-chart__table caption { margin-block-end: var(--zx-space-2); font-weight: 700; text-align: start; }
60
+ .zx-chart__table caption { margin-block-end: var(--zx-space-2); font-weight: var(--zx-weight-semibold); text-align: start; }
58
61
  .zx-chart__table th,
59
62
  .zx-chart__table td { border-block-end: 1px solid var(--zx-color-border); padding: var(--zx-space-2); text-align: end; }
60
63
  .zx-chart__table th:first-child,