@zeyos/zx 4.4.0 → 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 (182) hide show
  1. package/CHANGELOG.md +283 -0
  2. package/README.md +42 -10
  3. package/dist/types/components/activity-list/activity-list.d.ts +22 -0
  4. package/dist/types/components/app-sidebar/app-sidebar.d.ts +5 -3
  5. package/dist/types/components/avatar/avatar.d.ts +46 -7
  6. package/dist/types/components/badge/badge.d.ts +21 -1
  7. package/dist/types/components/button/button.d.ts +15 -0
  8. package/dist/types/components/chart/chart.d.ts +10 -0
  9. package/dist/types/components/checklist/checklist.d.ts +9 -0
  10. package/dist/types/components/code-editor/code-editor.d.ts +6 -17
  11. package/dist/types/components/datebox/date-range-box.d.ts +5 -1
  12. package/dist/types/components/datebox/datebox.d.ts +7 -2
  13. package/dist/types/components/dialog/dialog.d.ts +46 -6
  14. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  15. package/dist/types/components/entity-ref/entity-ref.d.ts +2 -2
  16. package/dist/types/components/field/field.d.ts +24 -2
  17. package/dist/types/components/fieldset/fieldset.d.ts +19 -1
  18. package/dist/types/components/file-item/file-item.d.ts +34 -6
  19. package/dist/types/components/form/form.d.ts +12 -1
  20. package/dist/types/components/kanban-view/kanban-card.d.ts +8 -0
  21. package/dist/types/components/launcher/launcher.d.ts +260 -15
  22. package/dist/types/components/list-toolbar/list-toolbar.d.ts +1 -1
  23. package/dist/types/components/menu-button/menu-button.d.ts +33 -5
  24. package/dist/types/components/message/message.d.ts +119 -17
  25. package/dist/types/components/modal/modal.d.ts +13 -2
  26. package/dist/types/components/select/color.d.ts +12 -0
  27. package/dist/types/components/select/glyphs.d.ts +124 -0
  28. package/dist/types/components/select/select.d.ts +11 -3
  29. package/dist/types/components/stat-tile/stat-tile.d.ts +16 -5
  30. package/dist/types/components/tabbox/tabbox.d.ts +9 -0
  31. package/dist/types/components/table/table.d.ts +46 -1
  32. package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
  33. package/dist/types/components/tree/tree.d.ts +13 -0
  34. package/dist/types/core/breakpoint.d.ts +1 -1
  35. package/dist/types/core/icons.d.ts +23 -25
  36. package/dist/types/core/motion.d.ts +59 -0
  37. package/dist/types/core/overlay-host.d.ts +15 -1
  38. package/dist/types/index.d.ts +5 -3
  39. package/dist/types/zeyos/connect.d.ts +6 -0
  40. package/dist/types/zeyos/form.d.ts +50 -9
  41. package/dist/types/zeyos/index.d.ts +1 -1
  42. package/dist/types/zeyos/query.d.ts +79 -0
  43. package/dist/types/zeyos/schema.d.ts +24 -1
  44. package/dist/types/zeyos/table.d.ts +100 -14
  45. package/dist/types/zeyos/view.d.ts +10 -0
  46. package/dist/zx-zeyos.esm.js +1621 -443
  47. package/dist/zx-zeyos.esm.min.js +53 -5
  48. package/dist/zx.css +1411 -660
  49. package/dist/zx.esm.js +1976 -703
  50. package/dist/zx.esm.min.js +56 -8
  51. package/dist/zx.global.js +1978 -705
  52. package/dist/zx.global.min.js +56 -8
  53. package/dist/zx.min.css +1 -1
  54. package/docs/api.json +219 -34
  55. package/docs/llms.md +472 -110
  56. package/docs/llms.txt +3 -3
  57. package/package.json +1 -1
  58. package/src/components/account-menu/account-menu.css +35 -10
  59. package/src/components/activity-item/activity-item.css +1 -1
  60. package/src/components/activity-item/activity-item.js +3 -0
  61. package/src/components/activity-list/activity-list.css +38 -3
  62. package/src/components/activity-list/activity-list.js +34 -0
  63. package/src/components/app-icon/app-icon.css +1 -1
  64. package/src/components/app-rail/app-rail.css +40 -79
  65. package/src/components/app-sidebar/app-sidebar.css +109 -174
  66. package/src/components/app-sidebar/app-sidebar.js +21 -6
  67. package/src/components/aurora/aurora.css +5 -3
  68. package/src/components/avatar/avatar.css +32 -7
  69. package/src/components/avatar/avatar.js +72 -8
  70. package/src/components/badge/badge.css +54 -2
  71. package/src/components/badge/badge.js +29 -2
  72. package/src/components/button/button.css +67 -9
  73. package/src/components/button/button.js +38 -0
  74. package/src/components/calendar/calendar.css +46 -46
  75. package/src/components/card/card.css +2 -2
  76. package/src/components/card-view/card-view.css +9 -7
  77. package/src/components/chart/chart.css +4 -1
  78. package/src/components/chart/chart.js +12 -0
  79. package/src/components/check-button/check-button.css +10 -2
  80. package/src/components/checklist/checklist.css +9 -2
  81. package/src/components/checklist/checklist.js +11 -5
  82. package/src/components/checklist/field-adapter.js +3 -1
  83. package/src/components/code-editor/code-editor.css +6 -5
  84. package/src/components/code-editor/code-editor.js +19 -1
  85. package/src/components/context-menu/context-menu.css +9 -4
  86. package/src/components/copy/copy-button.css +6 -0
  87. package/src/components/copy/copy-input.css +8 -3
  88. package/src/components/data-filter/data-filter.css +5 -4
  89. package/src/components/date-picker/date-picker.css +6 -6
  90. package/src/components/date-picker/date-range-picker.css +3 -3
  91. package/src/components/date-picker/time-picker.css +1 -1
  92. package/src/components/datebox/date-range-box.css +79 -2
  93. package/src/components/datebox/date-range-box.js +13 -2
  94. package/src/components/datebox/datebox.css +79 -2
  95. package/src/components/datebox/datebox.js +13 -2
  96. package/src/components/dialog/dialog.css +26 -0
  97. package/src/components/dialog/dialog.js +99 -17
  98. package/src/components/dropdown/dropdown.css +1 -1
  99. package/src/components/dropdown/dropdown.js +5 -3
  100. package/src/components/empty-state/empty-state.css +2 -2
  101. package/src/components/entity-ref/entity-ref.css +1 -1
  102. package/src/components/entity-ref/entity-ref.js +1 -1
  103. package/src/components/field/field.css +28 -9
  104. package/src/components/field/field.js +68 -26
  105. package/src/components/field-upload/field-upload.css +1 -1
  106. package/src/components/fieldset/fieldset.css +5 -3
  107. package/src/components/fieldset/fieldset.js +28 -5
  108. package/src/components/file-item/file-item.js +144 -10
  109. package/src/components/filter/filter.js +7 -3
  110. package/src/components/filter-panel/filter-panel.css +1 -1
  111. package/src/components/finder/finder.css +15 -13
  112. package/src/components/form/form.css +5 -4
  113. package/src/components/form/form.js +11 -2
  114. package/src/components/grid/grid.css +1 -1
  115. package/src/components/groupbox/groupbox.css +1 -1
  116. package/src/components/kanban-view/kanban-card.js +11 -3
  117. package/src/components/kanban-view/kanban-view.css +39 -15
  118. package/src/components/kanban-view/kanban-view.js +4 -4
  119. package/src/components/launcher/launcher.css +107 -25
  120. package/src/components/launcher/launcher.js +503 -41
  121. package/src/components/list-toolbar/list-toolbar.css +13 -8
  122. package/src/components/list-toolbar/list-toolbar.js +1 -1
  123. package/src/components/master-panel/master-panel.css +2 -0
  124. package/src/components/menu-button/menu-button.css +9 -4
  125. package/src/components/menu-button/menu-button.js +65 -9
  126. package/src/components/message/message.css +33 -3
  127. package/src/components/message/message.js +217 -15
  128. package/src/components/modal/modal.js +18 -3
  129. package/src/components/navigation-bar/navigation-bar.css +18 -9
  130. package/src/components/number-field/field-adapter.js +1 -0
  131. package/src/components/number-field/number-field.css +70 -0
  132. package/src/components/number-field/number-field.js +2 -0
  133. package/src/components/pagination/pagination.css +8 -6
  134. package/src/components/panel/panel.css +1 -1
  135. package/src/components/rating/rating.css +7 -0
  136. package/src/components/select/color.js +22 -0
  137. package/src/components/select/field-adapter.js +2 -0
  138. package/src/components/select/glyphs.js +165 -0
  139. package/src/components/select/select.css +138 -45
  140. package/src/components/select/select.js +83 -47
  141. package/src/components/sheet/sheet.css +11 -8
  142. package/src/components/slider/slider.css +16 -2
  143. package/src/components/slider/slider.js +1 -1
  144. package/src/components/sort-control/sort-control.css +4 -1
  145. package/src/components/stat-tile/stat-tile.css +41 -46
  146. package/src/components/stat-tile/stat-tile.js +17 -6
  147. package/src/components/tabbox/tabbox.css +32 -27
  148. package/src/components/tabbox/tabbox.js +5 -1
  149. package/src/components/table/table.css +104 -29
  150. package/src/components/table/table.js +90 -16
  151. package/src/components/tag-picker/tag-picker.css +83 -5
  152. package/src/components/tag-picker/tag-picker.js +25 -8
  153. package/src/components/timebox/timebox.css +22 -2
  154. package/src/components/toggle/toggle.css +12 -1
  155. package/src/components/toolbar/toolbar.js +2 -2
  156. package/src/components/tooltip/tooltip.css +4 -0
  157. package/src/components/tooltip/tooltip.js +10 -3
  158. package/src/components/tree/tree.css +25 -16
  159. package/src/components/tree/tree.js +31 -0
  160. package/src/components/value-list/value-list.css +3 -3
  161. package/src/components/view/record-view.js +1 -1
  162. package/src/core/breakpoint.js +1 -1
  163. package/src/core/icons.js +193 -60
  164. package/src/core/motion.js +147 -0
  165. package/src/core/overlay-host.js +21 -2
  166. package/src/index.js +5 -3
  167. package/src/internal/app-rail.js +1 -2
  168. package/src/zeyos/connect.js +6 -2
  169. package/src/zeyos/form.js +67 -27
  170. package/src/zeyos/index.js +1 -1
  171. package/src/zeyos/query.js +153 -0
  172. package/src/zeyos/schema.js +144 -27
  173. package/src/zeyos/table.js +68 -5
  174. package/src/zeyos/view.js +6 -0
  175. package/styles/base.css +56 -0
  176. package/styles/icons.css +11 -1
  177. package/styles/tokens/dark.css +113 -37
  178. package/styles/tokens/global.css +121 -27
  179. package/styles/tokens/semantic.css +100 -31
  180. package/styles/tokens/themes.css +7 -6
  181. package/styles/zx.css +0 -1
  182. 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,
@@ -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,
@@ -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
 
@@ -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,
@@ -1,5 +1,6 @@
1
1
  import { Component } from '../../core/component.js';
2
2
  import { h } from '../../core/dom.js';
3
+ import { prefersReducedMotion, watchMotion } from '../../core/motion.js';
3
4
  import { uid } from '../../core/util.js';
4
5
 
5
6
  /** @typedef {{label?: string, data?: unknown[], [key: string]: unknown}} ChartDataset */
@@ -9,6 +10,9 @@ import { uid } from '../../core/util.js';
9
10
  * @property {string} type Chart type.
10
11
  * @property {ChartData} data Chart data.
11
12
  * @property {Record<string, unknown>} options Engine-specific options.
13
+ * @property {boolean} reducedMotion Whether the chart must not animate: the operating system asks
14
+ * for reduced motion, or the host sits inside a `data-zx-motion="reduced"` region. An adapter turns
15
+ * its engine's own animation off when this is true; `ChartJsAdapter` sets `animation: false`.
12
16
  * @property {(detail: ChartSelectDetail) => void} onSelect Point-selection callback.
13
17
  */
14
18
  /**
@@ -145,6 +149,9 @@ export class Chart extends Component {
145
149
 
146
150
  this._observer = typeof ResizeObserver === 'function' ? new ResizeObserver(() => this.resize()) : null;
147
151
  this._observer?.observe(viewport);
152
+ // The engine tweens in script, where no stylesheet can reach it: when motion is reduced, or
153
+ // stops being reduced, the mounted chart is updated with the new answer in its spec.
154
+ this._stopWatchingMotion = watchMotion(root, () => this._mountOrUpdate(false));
148
155
  return root;
149
156
  }
150
157
 
@@ -232,6 +239,7 @@ export class Chart extends Component {
232
239
  this._destroyed = true;
233
240
  const original = this._original;
234
241
  this._observer?.disconnect();
242
+ this._stopWatchingMotion?.();
235
243
  this._destroyHandle();
236
244
  super.destroy();
237
245
  if (!this._createdRoot && original) {
@@ -277,6 +285,7 @@ export class Chart extends Component {
277
285
  ...themeChartOptions(/** @type {HTMLElement} */ (this.el)),
278
286
  ...cloneChartValue(this._chartOptions)
279
287
  },
288
+ reducedMotion: prefersReducedMotion(this.el),
280
289
  onSelect: (detail) => this.emit('select', detail)
281
290
  };
282
291
  }
@@ -386,6 +395,9 @@ function chartJsConfig(spec, defaults, getInstance) {
386
395
  ...cloneChartValue(defaults),
387
396
  ...supplied
388
397
  };
398
+ // Reduced motion wins over any animation the application configured: a person who asked for
399
+ // less motion gets it from every chart, not only from the ones that remembered to ask.
400
+ if (spec.reducedMotion) options.animation = false;
389
401
  const originalClick = options.onClick;
390
402
  options.onClick = (event, elements, chart) => {
391
403
  if (typeof originalClick === 'function') originalClick(event, elements, chart);
@@ -11,6 +11,7 @@
11
11
  padding-inline: var(--zx-control-pad-x);
12
12
  font: inherit;
13
13
  font-size: var(--zx-control-font-size);
14
+ font-weight: var(--zx-control-font-weight);
14
15
  cursor: pointer;
15
16
  }
16
17
 
@@ -18,9 +19,16 @@
18
19
  background: var(--zx-color-bg-hover);
19
20
  }
20
21
 
22
+ /* Pressed is a state the button is in, so the button itself goes neutral — the current fill, a
23
+ stronger border, the full text colour — and only the check glyph, which is the mark, keeps the
24
+ accent, as a checkbox would. */
21
25
  .zx-check-button[aria-pressed="true"] {
22
- border-color: var(--zx-color-accent);
23
- background: var(--zx-color-bg-selected);
26
+ border-color: var(--zx-color-border-strong);
27
+ background: var(--zx-color-bg-current);
28
+ color: var(--zx-color-text);
29
+ }
30
+
31
+ .zx-check-button__on {
24
32
  color: var(--zx-color-accent);
25
33
  }
26
34
 
@@ -7,7 +7,9 @@
7
7
  }
8
8
 
9
9
  .zx-checklist__label {
10
- font-weight: 650;
10
+ color: var(--zx-color-text-muted);
11
+ font-size: var(--zx-text-sm);
12
+ font-weight: var(--zx-weight-medium);
11
13
  }
12
14
 
13
15
  .zx-checklist__search {
@@ -31,10 +33,12 @@
31
33
  display: flex;
32
34
  align-items: center;
33
35
  gap: var(--zx-space-2);
34
- min-block-size: var(--zx-control-height);
36
+ /* The same row as a listbox option. */
37
+ min-block-size: calc(var(--zx-control-height) - 2px);
35
38
  border-radius: var(--zx-radius-sm);
36
39
  cursor: pointer;
37
40
  padding: var(--zx-space-1) var(--zx-space-2);
41
+ line-height: 1.35;
38
42
  }
39
43
 
40
44
  .zx-checklist__item:hover {
@@ -45,8 +49,11 @@
45
49
  background: var(--zx-color-bg-selected);
46
50
  }
47
51
 
52
+ /* The base control height is for text fields; a checkbox that inherited it would make every row
53
+ a field tall. */
48
54
  .zx-checklist__item input {
49
55
  flex: none;
56
+ min-block-size: 0;
50
57
  accent-color: var(--zx-color-accent);
51
58
  }
52
59
 
@@ -13,6 +13,9 @@ import { matchItems } from '../select/filter.js';
13
13
  * @property {boolean} [search=true] Whether the search field is shown.
14
14
  * @property {number} [height=280] Maximum list height in pixels.
15
15
  * @property {boolean} [defaultChecked=false] Fallback initial checked state.
16
+ * @property {boolean} [hideLabel=false] Whether the heading is left out. The group keeps the
17
+ * heading text as its accessible name (`aria-label`); a Field labelling the checklist names it
18
+ * instead, which is why the `checklist` field type sets this.
16
19
  * @property {(() => Promise<ChecklistItem[]>|ChecklistItem[])|null} [load=null] Async item loader.
17
20
  * @property {Record<string, string>|Record<string, Record<string, string>>} [msg] Localized messages.
18
21
  * @property {(event: CustomEvent<ChecklistChangeDetail>) => void} [onchange] Change listener.
@@ -40,6 +43,7 @@ export class Checklist extends Component {
40
43
  search: true,
41
44
  height: 280,
42
45
  defaultChecked: false,
46
+ hideLabel: false,
43
47
  load: null
44
48
  };
45
49
 
@@ -53,15 +57,16 @@ export class Checklist extends Component {
53
57
  const root = /** @type {HTMLElement} */ (this.el ?? h('div'));
54
58
  this.el = root;
55
59
  if (!this._createdRoot) this._originalChildren = Array.from(root.childNodes);
56
- for (const name of ['role', 'aria-labelledby', 'data-state']) {
60
+ for (const name of ['role', 'aria-label', 'aria-labelledby', 'data-state']) {
57
61
  this._originalAttributes.set(name, root.getAttribute(name));
58
62
  }
59
63
 
64
+ const labelText = this._message('checklist.label', 'Checklist');
60
65
  const labelId = uid('zx-checklist-label');
61
- const title = h('div', {
66
+ const title = this.options.hideLabel ? null : h('div', {
62
67
  class: 'zx-checklist__label',
63
68
  id: labelId
64
- }, this._message('checklist.label', 'Checklist'));
69
+ }, labelText);
65
70
  const search = h('input', {
66
71
  ref: 'search',
67
72
  class: 'zx-checklist__search',
@@ -76,9 +81,10 @@ export class Checklist extends Component {
76
81
  class: 'zx-checklist__list'
77
82
  });
78
83
  list.style.maxBlockSize = `${Math.max(0, Number(this.options.height) || 0)}px`;
79
- root.replaceChildren(title, search, list);
84
+ root.replaceChildren(...[title, search, list].filter(Boolean));
80
85
  root.setAttribute('role', 'group');
81
- root.setAttribute('aria-labelledby', labelId);
86
+ if (title) root.setAttribute('aria-labelledby', labelId);
87
+ else root.setAttribute('aria-label', labelText);
82
88
 
83
89
  this.listen(search, 'input', () => this.search(/** @type {HTMLInputElement} */ (search).value));
84
90
  this.listen(list, 'change', (event) => {
@@ -7,7 +7,9 @@ import { Checklist } from './checklist.js';
7
7
  */
8
8
  export function registerChecklistFieldAdapter() {
9
9
  Field.register('checklist', (field, options) => {
10
- const checklist = field.own(new Checklist(null, { ...(options.props ?? {}) }));
10
+ // The Field's label names the list (`aria-labelledby`), so the checklist draws no heading of
11
+ // its own under it.
12
+ const checklist = field.own(new Checklist(null, { hideLabel: true, ...(options.props ?? {}) }));
11
13
  let disabled = false;
12
14
  let setting = false;
13
15
  const syncDisabled = () => {
@@ -17,17 +17,18 @@
17
17
  min-block-size: var(--zx-control-height);
18
18
  padding-inline: var(--zx-space-3);
19
19
  border-block-end: 1px solid var(--zx-color-border);
20
- background: var(--zx-color-bg-subtle);
20
+ background: var(--zx-color-bg-muted);
21
21
  color: var(--zx-color-text-muted);
22
22
  font-size: var(--zx-text-xs);
23
23
  }
24
24
 
25
+ /* The language is an identifier (`json`, `sql`), so it is shown as one — in the mono face, as
26
+ written — rather than shouted in letter-spaced capitals. */
25
27
  .zx-code-editor__language {
26
28
  overflow: hidden;
27
- font-weight: 600;
28
- letter-spacing: 0.04em;
29
+ font-family: var(--zx-font-mono);
30
+ font-weight: var(--zx-weight-medium);
29
31
  text-overflow: ellipsis;
30
- text-transform: uppercase;
31
32
  text-wrap: nowrap;
32
33
  }
33
34
 
@@ -59,7 +60,7 @@
59
60
  }
60
61
 
61
62
  .zx-code-editor[data-readonly="true"] {
62
- background: var(--zx-color-bg-subtle);
63
+ background: var(--zx-color-bg-muted);
63
64
  }
64
65
 
65
66
  .zx-code-editor[data-disabled="true"] {
@@ -19,10 +19,17 @@ import { h } from '../../core/dom.js';
19
19
  * @property {(event: CustomEvent<{value:string}>) => void} [onchange] Change listener.
20
20
  */
21
21
 
22
+ /** Keys that only modify the next one: pressing them is not the keystroke that ends a Tab release. */
23
+ const MODIFIER_KEYS = new Set(['Shift', 'Control', 'Alt', 'Meta', 'AltGraph', 'CapsLock', 'Fn', 'OS']);
24
+
22
25
  /**
23
26
  * Dependency-free source editor for structured text, Markdown, JSON and code. It deliberately uses
24
27
  * a native textarea: values remain text-safe, browser undo and IME behavior stay intact, and Tab /
25
28
  * Shift+Tab provide predictable indentation without a third-party editor runtime.
29
+ *
30
+ * Capturing Tab is what a code surface has to do, and it would be a keyboard trap if nothing undid
31
+ * it: Escape releases the capture until the next keystroke in the editor, so Escape then Tab (or
32
+ * Shift+Tab) moves focus out of the editor as it would leave any other field.
26
33
  * @fires CodeEditor#input
27
34
  * @fires CodeEditor#change
28
35
  * @extends {Component<CodeEditorOptions>}
@@ -81,8 +88,11 @@ export class CodeEditor extends Component {
81
88
  root.dataset.readonly = String(Boolean(this.options.readOnly));
82
89
  root.dataset.disabled = String(Boolean(this.options.disabled));
83
90
  root.replaceChildren(this._header, this._input);
91
+ /** Set by Escape: the next Tab moves focus instead of indenting. */
92
+ this._tabReleased = false;
84
93
 
85
94
  this.listen(this._input, 'keydown', (event) => this._handleKeydown(event));
95
+ this.listen(this._input, 'blur', () => { this._tabReleased = false; });
86
96
  this.listen(this._input, 'input', () => {
87
97
  this._updatePosition();
88
98
  this.emit('input', { value: this.getValue() });
@@ -139,7 +149,15 @@ export class CodeEditor extends Component {
139
149
 
140
150
  /** @param {KeyboardEvent} event @returns {void} */
141
151
  _handleKeydown(event) {
142
- if (event.key !== 'Tab' || event.altKey || event.ctrlKey || event.metaKey ||
152
+ if (event.isComposing || MODIFIER_KEYS.has(event.key)) return;
153
+ if (event.key === 'Escape') {
154
+ this._tabReleased = true;
155
+ return;
156
+ }
157
+ // Any other keystroke ends the release, the Tab it was for included.
158
+ const released = this._tabReleased;
159
+ this._tabReleased = false;
160
+ if (released || event.key !== 'Tab' || event.altKey || event.ctrlKey || event.metaKey ||
143
161
  this._input.readOnly || this._input.disabled) return;
144
162
  const indent = String(this.options.indent ?? '\t');
145
163
  if (!indent) return;
@@ -21,12 +21,16 @@
21
21
  align-items: center;
22
22
  gap: var(--zx-space-2);
23
23
  inline-size: 100%;
24
- min-block-size: var(--zx-control-height);
25
- border: 1px solid transparent;
24
+ /* A menu row sits a little under a control so a list of them reads lighter than a column of
25
+ fields; the radius is the smallest step, inset inside the panel's own. */
26
+ min-block-size: calc(var(--zx-control-height) - 2px);
27
+ border: 0;
28
+ border-radius: var(--zx-radius-sm);
26
29
  background: transparent;
27
- padding-inline: var(--zx-control-pad-x);
30
+ padding: var(--zx-space-1) var(--zx-space-2);
28
31
  color: inherit;
29
32
  font: inherit;
33
+ line-height: 1.35;
30
34
  text-align: start;
31
35
  text-decoration: none;
32
36
  }
@@ -117,8 +121,9 @@
117
121
  box-shadow: inset 0 0 0 2px var(--zx-color-bg-raised);
118
122
  }
119
123
 
124
+ /* A section label is a caption, never taller than the rows it introduces. */
120
125
  .zx-context-menu__heading {
121
- padding: var(--zx-space-2) var(--zx-control-pad-x) var(--zx-space-1);
126
+ padding: var(--zx-space-1) var(--zx-space-2);
122
127
  color: var(--zx-color-text-muted);
123
128
  font-size: var(--zx-text-xs);
124
129
  font-weight: 600;