@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.
- package/CHANGELOG.md +438 -0
- package/README.md +49 -10
- package/dist/types/components/activity-item/activity-item.d.ts +351 -0
- package/dist/types/components/activity-list/activity-list.d.ts +217 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +33 -3
- package/dist/types/components/avatar/avatar.d.ts +46 -7
- package/dist/types/components/badge/badge.d.ts +21 -1
- package/dist/types/components/button/button.d.ts +23 -0
- package/dist/types/components/calendar/calendar.d.ts +19 -0
- package/dist/types/components/card/card.d.ts +7 -0
- package/dist/types/components/card-view/card-view.d.ts +11 -3
- package/dist/types/components/card-view/record-card.d.ts +7 -1
- package/dist/types/components/chart/chart.d.ts +10 -0
- package/dist/types/components/checklist/checklist.d.ts +9 -0
- package/dist/types/components/code-editor/code-editor.d.ts +149 -0
- package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
- package/dist/types/components/context-menu/context-menu.d.ts +18 -2
- package/dist/types/components/date-picker/date-picker.d.ts +8 -0
- package/dist/types/components/date-picker/time-picker.d.ts +7 -0
- package/dist/types/components/datebox/date-range-box.d.ts +5 -1
- package/dist/types/components/datebox/datebox.d.ts +7 -2
- package/dist/types/components/dialog/dialog.d.ts +75 -6
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
- package/dist/types/components/field/field.d.ts +24 -2
- package/dist/types/components/fieldset/fieldset.d.ts +19 -1
- package/dist/types/components/file-item/file-item.d.ts +262 -0
- package/dist/types/components/file-list/file-list.d.ts +171 -0
- package/dist/types/components/filter/filter.d.ts +91 -36
- package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
- package/dist/types/components/form/form.d.ts +12 -1
- package/dist/types/components/kanban-view/kanban-card.d.ts +146 -0
- package/dist/types/components/kanban-view/kanban-view.d.ts +170 -4
- package/dist/types/components/launcher/launcher.d.ts +278 -26
- package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
- package/dist/types/components/menu-button/menu-button.d.ts +37 -42
- package/dist/types/components/message/message.d.ts +126 -17
- package/dist/types/components/modal/modal.d.ts +61 -2
- package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
- package/dist/types/components/panel/panel.d.ts +7 -0
- package/dist/types/components/search/search.d.ts +7 -0
- package/dist/types/components/select/color.d.ts +12 -0
- package/dist/types/components/select/glyphs.d.ts +124 -0
- package/dist/types/components/select/select.d.ts +15 -3
- package/dist/types/components/sort-control/sort-control.d.ts +105 -0
- package/dist/types/components/stat-tile/stat-tile.d.ts +288 -0
- package/dist/types/components/tabbox/tabbox.d.ts +16 -0
- package/dist/types/components/table/table.d.ts +190 -1
- package/dist/types/components/table-view/table-view.d.ts +11 -5
- package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
- package/dist/types/components/timebox/timebox.d.ts +7 -0
- package/dist/types/components/tree/tree.d.ts +13 -0
- package/dist/types/components/value-list/value-list.d.ts +8 -0
- package/dist/types/components/view/record-view.d.ts +96 -5
- package/dist/types/core/breakpoint.d.ts +1 -1
- package/dist/types/core/icons.d.ts +37 -22
- package/dist/types/core/motion.d.ts +59 -0
- package/dist/types/core/overlay-host.d.ts +15 -1
- package/dist/types/index.d.ts +16 -3
- package/dist/types/internal/app-rail.d.ts +10 -0
- package/dist/types/internal/menu-items.d.ts +134 -0
- package/dist/types/zeyos/connect.d.ts +6 -0
- package/dist/types/zeyos/form.d.ts +50 -9
- package/dist/types/zeyos/index.d.ts +1 -1
- package/dist/types/zeyos/query.d.ts +79 -0
- package/dist/types/zeyos/schema.d.ts +24 -1
- package/dist/types/zeyos/table.d.ts +100 -14
- package/dist/types/zeyos/view.d.ts +10 -0
- package/dist/zx-zeyos.esm.js +2206 -489
- package/dist/zx-zeyos.esm.min.js +56 -1
- package/dist/zx.css +3322 -724
- package/dist/zx.esm.js +12244 -5809
- package/dist/zx.esm.min.js +58 -3
- package/dist/zx.global.js +12246 -5811
- package/dist/zx.global.min.js +58 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +1683 -146
- package/docs/llms.md +777 -110
- package/docs/llms.txt +14 -8
- package/package.json +1 -1
- package/src/components/account-menu/account-menu.css +35 -10
- package/src/components/activity-item/activity-item.css +137 -0
- package/src/components/activity-item/activity-item.js +602 -0
- package/src/components/activity-list/activity-list.css +99 -0
- package/src/components/activity-list/activity-list.js +409 -0
- package/src/components/app-icon/app-icon.css +1 -1
- package/src/components/app-rail/app-rail.css +191 -22
- package/src/components/app-sidebar/app-sidebar.css +349 -24
- package/src/components/app-sidebar/app-sidebar.js +86 -11
- package/src/components/aurora/aurora.css +5 -3
- package/src/components/avatar/avatar.css +32 -7
- package/src/components/avatar/avatar.js +72 -8
- package/src/components/badge/badge.css +54 -2
- package/src/components/badge/badge.js +29 -2
- package/src/components/button/button.css +74 -8
- package/src/components/button/button.js +44 -1
- package/src/components/calendar/calendar.css +46 -46
- package/src/components/calendar/calendar.js +33 -3
- package/src/components/card/card.css +2 -2
- package/src/components/card/card.js +12 -1
- package/src/components/card-view/card-view.css +10 -7
- package/src/components/card-view/card-view.js +25 -9
- package/src/components/card-view/record-card.js +7 -3
- package/src/components/chart/chart.css +4 -1
- package/src/components/chart/chart.js +12 -0
- package/src/components/check-button/check-button.css +10 -2
- package/src/components/checklist/checklist.css +9 -2
- package/src/components/checklist/checklist.js +11 -5
- package/src/components/checklist/field-adapter.js +3 -1
- package/src/components/code-editor/code-editor.css +68 -0
- package/src/components/code-editor/code-editor.js +306 -0
- package/src/components/code-editor/field-adapter.js +34 -0
- package/src/components/context-menu/context-menu.css +87 -5
- package/src/components/context-menu/context-menu.js +22 -30
- package/src/components/copy/copy-button.css +6 -0
- package/src/components/copy/copy-input.css +8 -3
- package/src/components/data-filter/data-filter.css +5 -4
- package/src/components/date-picker/date-picker.css +6 -6
- package/src/components/date-picker/date-picker.js +22 -8
- package/src/components/date-picker/date-range-picker.css +3 -3
- package/src/components/date-picker/month-picker.js +3 -3
- package/src/components/date-picker/time-picker.css +1 -1
- package/src/components/date-picker/time-picker.js +20 -8
- package/src/components/datebox/date-range-box.css +79 -2
- package/src/components/datebox/date-range-box.js +13 -2
- package/src/components/datebox/datebox.css +79 -2
- package/src/components/datebox/datebox.js +13 -2
- package/src/components/dialog/dialog.css +26 -0
- package/src/components/dialog/dialog.js +174 -70
- package/src/components/dropdown/dropdown.css +1 -1
- package/src/components/dropdown/dropdown.js +7 -5
- package/src/components/empty-state/empty-state.css +2 -2
- package/src/components/entity-ref/entity-ref.css +182 -0
- package/src/components/entity-ref/entity-ref.js +496 -0
- package/src/components/field/field.css +28 -9
- package/src/components/field/field.js +68 -26
- package/src/components/field-upload/field-upload.css +1 -1
- package/src/components/fieldset/fieldset.css +5 -3
- package/src/components/fieldset/fieldset.js +28 -5
- package/src/components/file-item/file-item.css +88 -0
- package/src/components/file-item/file-item.js +505 -0
- package/src/components/file-list/file-list.css +51 -0
- package/src/components/file-list/file-list.js +320 -0
- package/src/components/filter/filter.css +27 -1
- package/src/components/filter/filter.js +205 -47
- package/src/components/filter-panel/filter-panel.css +104 -0
- package/src/components/filter-panel/filter-panel.js +964 -0
- package/src/components/finder/finder.css +15 -13
- package/src/components/form/form.css +5 -4
- package/src/components/form/form.js +11 -2
- package/src/components/grid/grid.css +1 -1
- package/src/components/groupbox/groupbox.css +1 -1
- package/src/components/kanban-view/kanban-card.js +247 -0
- package/src/components/kanban-view/kanban-view.css +226 -8
- package/src/components/kanban-view/kanban-view.js +255 -12
- package/src/components/launcher/launcher.css +107 -25
- package/src/components/launcher/launcher.js +557 -63
- package/src/components/list-toolbar/list-toolbar.css +194 -0
- package/src/components/list-toolbar/list-toolbar.js +851 -0
- package/src/components/master-panel/master-panel.css +2 -0
- package/src/components/menu-button/menu-button.css +87 -5
- package/src/components/menu-button/menu-button.js +86 -46
- package/src/components/message/message.css +38 -5
- package/src/components/message/message.js +230 -17
- package/src/components/modal/modal.css +15 -0
- package/src/components/modal/modal.js +159 -3
- package/src/components/navigation-bar/navigation-bar.css +95 -11
- package/src/components/navigation-bar/navigation-bar.js +171 -4
- package/src/components/number-field/field-adapter.js +1 -0
- package/src/components/number-field/number-field.css +70 -0
- package/src/components/number-field/number-field.js +2 -0
- package/src/components/pagination/pagination.css +8 -6
- package/src/components/panel/panel.css +1 -1
- package/src/components/panel/panel.js +13 -2
- package/src/components/rating/rating.css +7 -0
- package/src/components/search/search.js +17 -5
- package/src/components/select/color.js +22 -0
- package/src/components/select/field-adapter.js +6 -1
- package/src/components/select/glyphs.js +165 -0
- package/src/components/select/select.css +138 -45
- package/src/components/select/select.js +86 -47
- package/src/components/sheet/sheet.css +11 -8
- package/src/components/slider/slider.css +16 -2
- package/src/components/slider/slider.js +1 -1
- package/src/components/sort-control/sort-control.css +20 -0
- package/src/components/sort-control/sort-control.js +140 -0
- package/src/components/stat-tile/stat-tile.css +208 -0
- package/src/components/stat-tile/stat-tile.js +601 -0
- package/src/components/tabbox/tabbox.css +32 -27
- package/src/components/tabbox/tabbox.js +17 -2
- package/src/components/table/table.css +155 -31
- package/src/components/table/table.js +386 -33
- package/src/components/table-view/table-view.css +8 -2
- package/src/components/table-view/table-view.js +21 -6
- package/src/components/tag-picker/tag-picker.css +86 -6
- package/src/components/tag-picker/tag-picker.js +25 -8
- package/src/components/timebox/timebox.css +22 -2
- package/src/components/timebox/timebox.js +18 -5
- package/src/components/toggle/toggle.css +12 -1
- package/src/components/toolbar/toolbar.js +2 -2
- package/src/components/tooltip/tooltip.css +4 -0
- package/src/components/tooltip/tooltip.js +10 -3
- package/src/components/tree/tree.css +25 -16
- package/src/components/tree/tree.js +31 -0
- package/src/components/value-list/value-list.css +3 -3
- package/src/components/value-list/value-list.js +22 -6
- package/src/components/view/record-view.css +5 -0
- package/src/components/view/record-view.js +100 -7
- package/src/core/breakpoint.js +1 -1
- package/src/core/icons.js +259 -57
- package/src/core/motion.js +147 -0
- package/src/core/overlay-host.js +21 -2
- package/src/index.js +30 -3
- package/src/internal/app-rail.js +18 -1
- package/src/internal/menu-items.js +142 -0
- package/src/zeyos/connect.js +6 -2
- package/src/zeyos/form.js +67 -27
- package/src/zeyos/index.js +1 -1
- package/src/zeyos/query.js +153 -0
- package/src/zeyos/schema.js +144 -27
- package/src/zeyos/table.js +68 -5
- package/src/zeyos/view.js +6 -0
- package/styles/base.css +56 -0
- package/styles/icons.css +11 -1
- package/styles/print.css +192 -0
- package/styles/tokens/dark.css +113 -37
- package/styles/tokens/global.css +121 -27
- package/styles/tokens/semantic.css +100 -31
- package/styles/tokens/themes.css +7 -6
- package/styles/zx.css +11 -1
- package/styles/tokens/density.css +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,444 @@ and friends remain the complete record.
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 5.0.0 — 2026-10-09
|
|
12
|
+
|
|
13
|
+
Xenon now has one geometry and a quieter finish. The cozy and compact view modes are gone; in their
|
|
14
|
+
place is a single, slightly tighter default whose spacing, corners, and control height are tokens a
|
|
15
|
+
product sets once. On top of it the visual language was refined against how well-made business
|
|
16
|
+
applications look today: "where you are" is a neutral fill rather than a block of accent colour,
|
|
17
|
+
status colours no longer borrow the brand green, chrome and canvas separate by tone instead of by
|
|
18
|
+
lines, labels are sentence case at medium weights, and icons are outlines.
|
|
19
|
+
|
|
20
|
+
The other half is what building twenty complete screens on the library asked of it. A layout
|
|
21
|
+
gallery of application templates and screen patterns — mail, an issue tracker, a knowledge base, AI
|
|
22
|
+
chat, an agent workspace, invoicing, inventory, workflows, infrastructure, CRM, and the screens
|
|
23
|
+
inside them — every one usable from a phone to a wide screen and clean under an accessibility
|
|
24
|
+
audit. Fixing what those screens found: some forty component defects, status colours that read as
|
|
25
|
+
text, nested dark themes, and focus that never falls to the page. And what they needed: motion as
|
|
26
|
+
a reader's setting, a command palette with pages, toasts that carry their action, busy buttons,
|
|
27
|
+
type-to-confirm, and public status and priority glyphs.
|
|
28
|
+
|
|
29
|
+
### Breaking
|
|
30
|
+
|
|
31
|
+
- **Form field keys are no longer element ids.** Control ids are generated per Form and Fieldset
|
|
32
|
+
instance (`<idPrefix>-<key>`; `idPrefix` makes them predictable), so a form mounted twice repeats
|
|
33
|
+
no id and a key such as `stage` never collides with `#stage` elsewhere. The key stays the field's
|
|
34
|
+
`name`, the native control's `name`, and its `data-field-id`; radio groups are named after the
|
|
35
|
+
control id. Code that looked a control up by `#<key>` reads `form.getField(key).controlId` (or
|
|
36
|
+
queries `[data-field-id="<key>"]`) instead. An explicit `id` that differs from the key is used as
|
|
37
|
+
given, and the legacy compatibility layer keeps key ids.
|
|
38
|
+
- **Density modes are removed.** `data-zx-density` (`cozy` | `compact`) no longer has any effect,
|
|
39
|
+
`styles/tokens/density.css` no longer ships, and no component carries density-specific rules.
|
|
40
|
+
Migration: drop the attribute. To tighten an application — or one region of it — set
|
|
41
|
+
`--zx-space-unit` and `--zx-control-height` instead, for example
|
|
42
|
+
`:root { --zx-space-unit: 3.5px; --zx-control-height: 28px; }`, which is close to what compact
|
|
43
|
+
used to do without shrinking the type.
|
|
44
|
+
- **`FileItem`'s `density` option is now `identitySize`** (`'sm'|'md'|'lg'`, the size of the
|
|
45
|
+
file's icon and name), and `FileList` items take the same name. The word now means one thing
|
|
46
|
+
nowhere in the library.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Every toast pauses while it holds focus as well as hover, resumes when neither applies, and
|
|
51
|
+
returns focus to where it came from if it closes while focused.
|
|
52
|
+
- Sheet slides on `--zx-ease-drawer`; KanbanView's drag preview and grabbed card take
|
|
53
|
+
`--zx-drag-shadow`. A solid primary button's pressed step is darker than its hover step.
|
|
54
|
+
- Launcher `select` and `error` details carry `page`; closing the launcher returns it to its root.
|
|
55
|
+
The status and priority glyph styles are `.zx-status-icon` and `.zx-priority-icon` (Select's
|
|
56
|
+
glyphs keep their old classes as well).
|
|
57
|
+
- **`Select.priority()` reads by height, not hue**: levels are four grey signal bars filled to the
|
|
58
|
+
level in muted ink, and only the highest is coloured — a danger square with "!". It offers "No
|
|
59
|
+
priority" (value null, message `priority.none`) at the head of the list; `clearable: false`
|
|
60
|
+
restores the old list, a required priority field leaves it out, and the legacy compatibility
|
|
61
|
+
select keeps its old list unless it allows empty values. Values and message keys are unchanged.
|
|
62
|
+
- **Quiet NumberField** start-aligns its value with the quiet values around it; both steppers sit
|
|
63
|
+
at the trailing end, shown on hover or focus.
|
|
64
|
+
- **Field `type: 'html'`** draws no input frame; display content keeps a control's height.
|
|
65
|
+
- **Toggle labels** start-align and wrap like text, the track level with the first line; a field
|
|
66
|
+
beside a taller one keeps its label and control at the top of its cell.
|
|
67
|
+
- **FileItem** shows a readable type ("PDF", "Image") instead of the MIME type and picks its icon
|
|
68
|
+
from the MIME type when the icon set has one.
|
|
69
|
+
- **AppSidebar** creates its own root as a `<div>` (the `<nav>` inside is the landmark), so it no
|
|
70
|
+
longer adds an unnamed complementary landmark; `getItems()` leaves out empty `children`.
|
|
71
|
+
- **Table** puts `data-column` on every header and body cell in every mode; **KanbanView**
|
|
72
|
+
assignee faces take Avatar's tint from the name (or a descriptor `tone`); the neutral soft
|
|
73
|
+
**Badge** is a wash of the text colour, visible on raised dark surfaces, and a small dotted
|
|
74
|
+
Badge has 12px text and a 4px gap.
|
|
75
|
+
- **ZeyOS enums read as labels** ("Invoiced", "Partly paid") in generated tables and forms; a
|
|
76
|
+
schema `{value, label}` is used as given. **ZeyOS date-only fields are calendar days** — indexed
|
|
77
|
+
`date`, `duedate`, `birthdate`, `datefrom`/`dateto` outside appointments and events, `datecancel`,
|
|
78
|
+
and `lastbilling` show no time and are stored as midnight in the instance's zone (`timeZone`,
|
|
79
|
+
default the browser's); `lastmodified` and the appointment, event, comment, record, and
|
|
80
|
+
document-version timestamps are date-times.
|
|
81
|
+
- **Spacing derives from one unit.** `--zx-space-1` … `--zx-space-8` are multiples of the new
|
|
82
|
+
`--zx-space-unit` (4px by default, so the steps are unchanged at 4–40px).
|
|
83
|
+
- **Corners are smaller and proportional.** `--zx-radius` is now `4px`, and `-sm`, `-md`, `-lg`,
|
|
84
|
+
and `-xl` are ×0.5, ×0.75, ×1, and ×1.5 of it — 2 / 3 / 4 / 6px, down from 3 / 5 / 7 / 11px — so a
|
|
85
|
+
theme that scales the base keeps every step in proportion. `--zx-control-radius` still follows
|
|
86
|
+
`-lg`. Panels that used `-xl` (Launcher, Sheet, the AppSidebar and AppRail items) use `-lg` or
|
|
87
|
+
`-md`; ValueList chips and record-card metadata chips are no longer pills, and the SortControl
|
|
88
|
+
direction button is a control rather than a circle.
|
|
89
|
+
- **Controls are 30px tall** (`--zx-control-height`, from 32px). `--zx-control-pad-x` stays 10px
|
|
90
|
+
and text sizes are unchanged.
|
|
91
|
+
- **Structured menus are tighter.** AppSidebar rows are one control tall (from control + 8px) with
|
|
92
|
+
2px between rows, 12px between groups, and a 3px corner. A text-only child starts under its
|
|
93
|
+
parent's label; a child with its own icon steps in 16px, just clear of the guide line, instead
|
|
94
|
+
of a whole icon column. The rail flyouts follow. TreeView indents 12px per level (from
|
|
95
|
+
18px) with a 4px block padding per row. MenuButton, ContextMenu, Select, TagPicker, Launcher,
|
|
96
|
+
Finder, Checklist, and the Table column menu share one row: 4px × 8px padding, the smallest
|
|
97
|
+
radius, panels at `--zx-radius-lg`, and section labels no taller than an item.
|
|
98
|
+
- **"Current" is neutral, and nothing is docked to an edge.** Where you are — the active
|
|
99
|
+
navigation item (AppSidebar, its rails and flyouts), the open TreeView node, the current Finder
|
|
100
|
+
column entry, the active tab in every Tabbox variant, the pressed ListToolbar view, the current
|
|
101
|
+
Calendar view, Launcher app and Pagination page — is a neutral `--zx-color-bg-current` fill with
|
|
102
|
+
the text colour at weight 600; the edge marker beside the active item is gone. What you have
|
|
103
|
+
*picked* (checked rows, chosen options, a multi-selection) keeps the accent tint. A rail item
|
|
104
|
+
whose flyout holds the active route takes the accent colour. Forced colours still use the
|
|
105
|
+
system's selected pair.
|
|
106
|
+
- **One solid accent per screen.** Solid accent is for the primary button; tab underlines, pressed
|
|
107
|
+
toggles, and decorative icons no longer use it. In dark, the primary button sits on the accent
|
|
108
|
+
600 step with white text (`--zx-color-accent-solid` / `--zx-color-on-accent-solid`) instead of
|
|
109
|
+
the bright 400 step.
|
|
110
|
+
- **Status green is its own colour.** `--zx-green-*` is a yellow-green status ramp that no longer
|
|
111
|
+
matches the default ZeyOS accent, so a "success" badge or chart segment never reads as branding.
|
|
112
|
+
The brand values moved to `--zx-emerald-*`, which the default accent points at.
|
|
113
|
+
- **Dark theme is layered.** Page, chrome, surface, raised, and overlay steps sit off near-black
|
|
114
|
+
(#1b1b1e → #313136), primary text is about 90% white, and borders are translucent white.
|
|
115
|
+
- **Quieter type.** Decorative upper-case and letter-spaced labels are gone from every component
|
|
116
|
+
(menu and Select groups, Launcher groups, StatTile labels, Calendar weekdays, Table headers, …);
|
|
117
|
+
row and label weights moved from 600 to 500, titles to 600–650, and UI text is set with
|
|
118
|
+
`--zx-tracking-tight` and Inter's `cv11`. Field labels and Fieldset legends are small, medium, and
|
|
119
|
+
muted, so values lead.
|
|
120
|
+
- **Tables** drop the header band (muted medium labels on the surface), divide rows with
|
|
121
|
+
`--zx-color-border-subtle`, and set numbers in tabular figures.
|
|
122
|
+
- **Avatars** fall back to a colour picked from the name (one of eight tones) with no ring, at
|
|
123
|
+
24 / 32 / 40px, and show one initial below 24px.
|
|
124
|
+
- **StatTile** labels are sentence case, values 24px tabular, the icon is a muted glyph without a
|
|
125
|
+
coloured chip, and tiles in a row line up whether or not they carry a sparkline.
|
|
126
|
+
- **EmptyState** draws its icon in `--zx-color-text-subtle` and its title semibold.
|
|
127
|
+
- **Danger is legible as text.** Light `--zx-color-danger` moves to the 600 step and the dark
|
|
128
|
+
danger tint is lighter, so danger ink keeps 4.5:1 on every surface and on its own tint, as the
|
|
129
|
+
other status colours do (now tested for all four in both themes and every preset).
|
|
130
|
+
- **The dark selected tint is lighter** (13% of the accent instead of 18%), so muted text on a
|
|
131
|
+
checked row or chosen option keeps 4.5:1 under every preset (now tested, light and dark).
|
|
132
|
+
- **Toasts lose their coloured leading-edge bar**; the kind shows in the icon and a tinted border,
|
|
133
|
+
as everywhere else nothing is docked to an edge.
|
|
134
|
+
- **Button key hints** are quieter by colour and weight instead of opacity, which left them below
|
|
135
|
+
4.5:1 on a solid primary button.
|
|
136
|
+
- **Select.entity** shows an entity without a colour as a neutral tile with a muted glyph; before,
|
|
137
|
+
the glyph was white on the pale accent tint and could not be seen.
|
|
138
|
+
- **Icons are Lucide outlines.** The bundled set renders as strokes in `currentColor` (ISC; a
|
|
139
|
+
1.75-unit stroke per 24 that never thins below 1px), with every existing name kept. Bundles keep
|
|
140
|
+
the licence notice. A chosen Rating star is drawn solid.
|
|
141
|
+
- **The theme studio's Density section is now Spacing**: a slider for `--zx-space-unit` (3–6px).
|
|
142
|
+
The radius slider sets `--zx-radius` in pixels (0–10px), the standard recipes carry a spacing
|
|
143
|
+
unit instead of a density, Copy CSS exports the unit, and a theme saved by an earlier studio
|
|
144
|
+
still loads.
|
|
145
|
+
|
|
146
|
+
### Added
|
|
147
|
+
|
|
148
|
+
- **Motion as a setting.** `data-zx-motion="reduced"` on any element stops motion inside it: the
|
|
149
|
+
duration tokens become `0ms` and a base rule stops CSS animations and transitions, while state
|
|
150
|
+
changes still apply; the system preference zeroes the tokens too. `prefersReducedMotion(element)`,
|
|
151
|
+
`watchMotion(element, fn, { signal, immediate })`, and `MOTION_ATTRIBUTE` let script follow it;
|
|
152
|
+
Chart passes `reducedMotion` to its adapter and `ChartJsAdapter` turns animation off under it.
|
|
153
|
+
- `--zx-ease-spring` (a small overshoot) and `--zx-ease-drawer` (a decisive ease-out) beside
|
|
154
|
+
`--zx-ease`, and `--zx-drag-shadow` for an item being dragged.
|
|
155
|
+
- **Launcher pages.** An item with `items` (an array, or a loader `(query, { signal })`) opens a
|
|
156
|
+
nested page: a scope chip in the input, Backspace, ArrowLeft, or × to go back, "⌫ Back" in the
|
|
157
|
+
footer, `open({ page })`, `back()`, `getPage()`, and a `page` event. Items take a `hint` (muted
|
|
158
|
+
text at the end of the row), `shortcut` key caps, and `keys` for `aria-keyshortcuts`.
|
|
159
|
+
- **Message `action`** (`{ label, onclick, kind }`, a small button that runs and closes the toast;
|
|
160
|
+
a toast with an action stays at least 8 seconds) and **`leading`** (a node such as an Avatar in
|
|
161
|
+
place of the kind icon).
|
|
162
|
+
- **`Dialog.confirm({ confirmText })`** — type-to-confirm: a labelled input that has focus, and a
|
|
163
|
+
confirm button and Enter that work only on an exact match.
|
|
164
|
+
- **Busy buttons.** `button({ busy })` and `setButtonBusy(button, busy)` show a spinner in place of
|
|
165
|
+
the icon, set `aria-busy`, and ignore activation while the action runs — but keep the button
|
|
166
|
+
focusable, so focus does not fall to the page as it does from a disabled button.
|
|
167
|
+
- **`statusIcon(status)` and `priorityIcon(level)`**, the glyphs `Select.status()` and
|
|
168
|
+
`Select.priority()` draw, for lists, boards, and filters; decorative unless given a `label`.
|
|
169
|
+
- `idPrefix` on Form and Fieldset; Field `name`, `field.name`, and `field.controlId`.
|
|
170
|
+
- Checklist `hideLabel`; TagPicker `toneKey` (default `'tone'`), colouring a tag the way a Badge
|
|
171
|
+
`tone` does; ActivityList `variant: 'compact'` for cards narrower than 30rem; Table column
|
|
172
|
+
`ariaLabel` for a blank or terse header; FileItem `typeLabel`; `Dialog.prompt` `okLabel` and
|
|
173
|
+
`cancelLabel`.
|
|
174
|
+
- `MenuButton.open({ returnFocus })` (also on `focusFirst()` and `focusLast()`) and
|
|
175
|
+
`Message.disposeRegion(scope)`.
|
|
176
|
+
- ZeyOS: `zeyosTable` passes Table options through (`variant`, `zebra`, `stickyHeader`,
|
|
177
|
+
`responsive`, `growing`, `emptyText`, `rowClass`, `rowKind(s)`, the column chooser, and the Table
|
|
178
|
+
listeners; editing, row reordering, and hierarchy stay out because the binding never persists
|
|
179
|
+
them); `timeZone` and per-field `formats` on `zeyosTable`, `zeyosForm`, `zeyosView`, and
|
|
180
|
+
`resolveFields`; `unixSecondsToCalendarDay()` and `calendarDayToUnixSeconds()`; `zeyosForm`
|
|
181
|
+
`scope` and `notify`.
|
|
182
|
+
- **Colour roles:** `--zx-color-bg-current`, `--zx-color-bg-chrome`, `--zx-color-border-subtle`,
|
|
183
|
+
`--zx-color-text-subtle`, the categorical tones `--zx-color-tone-{blue,teal,green,amber,orange,
|
|
184
|
+
red,pink,violet,slate}-{bg,fg}`, and the chart series `--zx-color-chart-1` … `-8`, whose first
|
|
185
|
+
series is deliberately not the accent. Contrast is tested in both themes and all six presets.
|
|
186
|
+
- **Type tokens:** `--zx-text-3xl` (30px), `--zx-weight-medium`, `--zx-weight-semibold`,
|
|
187
|
+
`--zx-tracking-tight`, `--zx-tracking-title`.
|
|
188
|
+
- **Quiet fields:** inside any `[data-zx-fields="quiet"]` container, native fields and Select,
|
|
189
|
+
TagPicker, Datebox, DateRangeBox, NumberField, and Timebox show their frame only on hover and
|
|
190
|
+
focus — property panels read as data, not as a wall of boxes.
|
|
191
|
+
- `Table` / `TableView` `variant: 'plain'` (no frame, no header band) for tables inside cards;
|
|
192
|
+
`badge({ tone })` with the categorical tones (and `BADGE_TONES`); `Avatar` `tone`, `avatarTone()`
|
|
193
|
+
and `AVATAR_TONES`; `StatTile` `caption`, read with the value.
|
|
194
|
+
- `registerIcons()` accepts outline glyphs as `[viewBox, path, 'stroke']`; `[viewBox, path]` pairs
|
|
195
|
+
still render filled.
|
|
196
|
+
- `Tabbox` `label`, the tab list's accessible name.
|
|
197
|
+
|
|
198
|
+
### Fixed
|
|
199
|
+
|
|
200
|
+
- A destructive `Dialog.confirm` started focus on the destructive button; it starts on Cancel, the
|
|
201
|
+
least destructive choice (type-to-confirm starts in its input).
|
|
202
|
+
- On a phone, toasts covered the header's controls; they rise from the foot of the screen there.
|
|
203
|
+
- A ghost Button showed no focus ring: its `box-shadow: none` outranked `:focus-visible`.
|
|
204
|
+
- Select's loading spinner never turned (it read an undefined duration token).
|
|
205
|
+
- The Launcher's search row could push its close button off a narrow screen.
|
|
206
|
+
- A `[data-zx-theme="dark"]` region on a light page inherited light glass, overlays, hover and
|
|
207
|
+
current fills, tone tints, and focus ring: colours derived from other theme colours were resolved
|
|
208
|
+
on `:root` only. They are restated on every theme element now; geometry overrides on `:root`
|
|
209
|
+
still reach nested regions.
|
|
210
|
+
- Overlays (Dropdown, Tooltip, MenuButton, ContextMenu, Modal, Dialog, Sheet, Launcher) created before their
|
|
211
|
+
anchor or scope was in the document parked their panel on `<body>`, outside the theme scope; they
|
|
212
|
+
find their host on first open.
|
|
213
|
+
- Choosing a MenuButton item dropped focus to `<body>`; it returns to the trigger. CodeEditor
|
|
214
|
+
trapped the keyboard; Escape then Tab leaves it, as documented.
|
|
215
|
+
- Floating Message regions kept sending toasts into an emptied host and were never removed.
|
|
216
|
+
- Table and Grid number and date editors select their content on entry (typing "6" over "1.00"
|
|
217
|
+
gives 6); sortable headers use the same font as the others; no scrollbar gutter is reserved on a
|
|
218
|
+
table that does not scroll; a blank header has an accessible name. TreeView type-ahead calls
|
|
219
|
+
`preventDefault` and leaves text controls in rows alone.
|
|
220
|
+
- Table's selection checkboxes and row-reorder handles sit in the middle of their cell. They rode a
|
|
221
|
+
few pixels high on the text baseline, and the cell padding pushed them off the centre of their
|
|
222
|
+
control-height column, in a fixed layout past its edge.
|
|
223
|
+
- NumberField, Datebox, and DateRangeBox fill a Field's control column; clear-button padding is
|
|
224
|
+
reserved only when `clearable`, and a disabled Datebox or DateRangeBox shows no clear button.
|
|
225
|
+
Slider end labels stay inside the component. A Checklist inside a Field no longer repeats its
|
|
226
|
+
heading.
|
|
227
|
+
- `colorKey` on `Select.entity()` and TagPicker accepts token references (`var(--zx-…)`). Clicking a
|
|
228
|
+
read-only Select no longer draws the keyboard focus ring; a disabled Select fades like a disabled
|
|
229
|
+
Field; a read-only TagPicker shows only its tags.
|
|
230
|
+
- `collapsible: false` still showed AppSidebar's minimise button. copyButton's status line and
|
|
231
|
+
CopyInput's hidden label were positioned outside their control.
|
|
232
|
+
- A Field whose adapter returns a wrapper (a `custom` field holding a component) named the
|
|
233
|
+
wrapper, which cannot carry a name; its label, description, and validity now reach the first
|
|
234
|
+
unnamed form control inside it, or the adapter's new `labelTarget`.
|
|
235
|
+
- Launcher ran an item's command before closing, so closing put focus back on an element the
|
|
236
|
+
command had just redrawn or moved focus away from; it closes first now.
|
|
237
|
+
- A MenuButton's menu had no accessible name; it is labelled by its trigger, as the APG pattern
|
|
238
|
+
has it. NumberField no longer swallows Mod+Enter (and other chords), so a form or dialog's submit
|
|
239
|
+
shortcut works from a number field. Datebox and DateRangeBox were 2px taller than the text input
|
|
240
|
+
beside them; every control is one control height.
|
|
241
|
+
- A Tooltip placed beside an anchor near the edge of the screen squeezed to a word per line
|
|
242
|
+
instead of moving: it now takes the other side, or goes above or below when neither side fits.
|
|
243
|
+
- A Chart in a narrow card overflowed it (its 220px minimum height became a 587px minimum width
|
|
244
|
+
through the aspect ratio); it grows taller instead. A StatTile delta keeps its figure on one line
|
|
245
|
+
in a narrow tile.
|
|
246
|
+
- `zeyosTable` showed a due date as a date-time whose hour moved with daylight saving, and
|
|
247
|
+
`zeyosForm` edited it as one; `zeyosForm.save()` raised its toast wherever focus was.
|
|
248
|
+
- The AccountMenu trigger rendered as a centred, boxed card because `menu-button.css` loaded after
|
|
249
|
+
`account-menu.css`; it is a flat row again.
|
|
250
|
+
- CodeEditor referenced `--zx-color-bg-subtle`, which never existed.
|
|
251
|
+
- The Marque Gold preset's accent text now reaches 4.5:1 on the light chrome tone.
|
|
252
|
+
- A sortable end-aligned Table column put its header label at the start, away from its figures;
|
|
253
|
+
the label now sits at the end with the sort arrow before it.
|
|
254
|
+
- ActivityItem's heading read the actor and title as one word ("Jonas Weberset…") to assistive
|
|
255
|
+
technology; a space now separates them.
|
|
256
|
+
- Table's Columns chooser, RecordView's Fields chooser, KanbanView's undo and redo, and Filter's
|
|
257
|
+
actions used a `zx-button` class no stylesheet defines, so they rendered as bare browser buttons;
|
|
258
|
+
they are small Zx buttons now (ghost in toolbars, primary for Apply).
|
|
259
|
+
|
|
260
|
+
### Website
|
|
261
|
+
|
|
262
|
+
- The application layouts moved from the documentation sidebar to a gallery of their own
|
|
263
|
+
(`layouts.html`), with a live thumbnail per layout, a near-full-screen view with its source, and a
|
|
264
|
+
standalone page (`layout.html#<id>`) for opening one in its own tab. Nine complete application
|
|
265
|
+
templates join the eight screen patterns, which are rebuilt on the same application shell.
|
|
266
|
+
- The documentation, gallery, and theme studio share the library's look: navigation on the chrome
|
|
267
|
+
tone, neutral current entries, sentence-case labels, hairline example cards, and code and API
|
|
268
|
+
tables drawn like the refined Table.
|
|
269
|
+
- New in the gallery: an **agent workspace** template — agents with live presence, editor tabs, a
|
|
270
|
+
plan and execution log with hand-offs, approvals as toasts that carry their action, a command
|
|
271
|
+
palette with pages, a bottom panel, and a status bar — and two screen patterns, **agent chat**
|
|
272
|
+
(tool calls, an approval that blocks the run, sources, and the run beside the thread) and
|
|
273
|
+
**system states** (every empty, loading, error, validation, and confirmation state, with a
|
|
274
|
+
switch to go offline). The AI chat template shows its work: tool steps, sources, artifacts with
|
|
275
|
+
versions, regenerate and branch, and `@agent` mentions.
|
|
276
|
+
- Every layout works from a phone to a wide screen: below 1180px the inspector and below 860px
|
|
277
|
+
the navigation become drawers, and on a phone a layout shows its list or its record with a way
|
|
278
|
+
back. All seventeen pass an accessibility audit — named controls and landmarks, text contrast,
|
|
279
|
+
visible focus, heading order — in both themes, wide and narrow.
|
|
280
|
+
- The theme studio has a Motion setting (System or Reduced), kept across the whole site as a
|
|
281
|
+
reader's preference, and a Button states card showing every kind in every state.
|
|
282
|
+
- The site self-hosts Inter as a variable font (SIL OFL), so every weight renders as designed and no
|
|
283
|
+
font request leaves the site.
|
|
284
|
+
- The theme studio offers more to build from. Eleven neutral tints — Neutral, Zinc, Stone, Cool,
|
|
285
|
+
Mist, Sage, Olive, Warm, Taupe, Mauve, and Accent — are picked from swatches of the ramp each
|
|
286
|
+
would produce, and a strength control scales any of them from grey to twice its colour; every
|
|
287
|
+
tint keeps the text roles legible at full strength. The typeface list grows from six system
|
|
288
|
+
stacks to eleven, drawn in their own type, plus a custom stack for a brand font, and the code
|
|
289
|
+
font (`--zx-font-mono`) is a choice of its own.
|
|
290
|
+
- Themes can be saved and loaded as JSON. Export writes a `zx-theme` file — the settings, plus the
|
|
291
|
+
custom properties they produce — to copy or download; Import takes one pasted, dropped, or chosen,
|
|
292
|
+
loads it even when a value is out of range or unknown, and says what it adjusted.
|
|
293
|
+
|
|
294
|
+
## 4.4.0 — 2026-09-22
|
|
295
|
+
|
|
296
|
+
A large release in two halves. The first adds capability: a dependency-free code editor, the
|
|
297
|
+
record primitives (`EntityRef`, `FileItem`/`FileList`, `ActivityItem`/`ActivityList`), kanban
|
|
298
|
+
movement and workflow policy, and richer action menus. The second is what building a real
|
|
299
|
+
application on the library found missing — group rows, list controls, a filter panel driven by
|
|
300
|
+
server metadata, a metric tile, and the long tail of strings a translated product could not
|
|
301
|
+
reach.
|
|
302
|
+
|
|
303
|
+
Nothing here is a breaking change. Every new option defaults to the previous behaviour, and every
|
|
304
|
+
English string a translator can now reach keeps its exact previous wording when no translator is
|
|
305
|
+
installed.
|
|
306
|
+
|
|
307
|
+
### Added
|
|
308
|
+
|
|
309
|
+
- **Structured text no longer requires an editor dependency.** `CodeEditor` keeps source in a
|
|
310
|
+
native textarea with browser undo and IME behavior, adds Tab/Shift+Tab indentation, language
|
|
311
|
+
metadata, line/column feedback, read-only and disabled states, and a `code` Form field adapter.
|
|
312
|
+
It never executes or injects the value; rich HTML authoring remains a separate policy surface.
|
|
313
|
+
- **Reusable record primitives cover dense identity, files, and activity.** `EntityRef` presents
|
|
314
|
+
linked or static identity with labelled metadata and injected actions; `FileItem`/`FileList`
|
|
315
|
+
cover durable, temporary, waiting, progress, MIME, size, download, loading, and empty states;
|
|
316
|
+
`ActivityItem`/`ActivityList` cover actor, time, content, attachments, actions, stable grouping,
|
|
317
|
+
and incremental feed updates. Zx owns safe presentation and cancelable interaction boundaries;
|
|
318
|
+
applications retain routing, authorization, transport, posting, reactions, and persistence.
|
|
319
|
+
- **Action menus now carry business metadata without becoming free-form popovers.** MenuButton and
|
|
320
|
+
ContextMenu share headings, object separators, safe native links, descriptions, badges,
|
|
321
|
+
shortcuts, text/Node adornments, and checked/radio menu-item roles. Existing flat items and
|
|
322
|
+
`'-'` separators are unchanged.
|
|
323
|
+
- **Kanban cards carry the anatomy an operational board needs.** New read-only projections put an
|
|
324
|
+
`entityIcon` and `identifier` on a card head beside `status` and `priority` indicators, and a
|
|
325
|
+
`progress` meter and `assignees` avatars on a card footer. `priorityTones` and `statusTones` map
|
|
326
|
+
a value to a semantic tone as data rather than through a renderer, `progressMax` sets the
|
|
327
|
+
completion scale explicitly, and `maxAvatars` bounds the avatar stack. A board that sets none of
|
|
328
|
+
them renders exactly the card it rendered in 4.3.4.
|
|
329
|
+
|
|
330
|
+
- **`FilterPanel` — typed filters from server metadata.** Takes the `{key: {type, label,
|
|
331
|
+
options, min, max}}` map a list endpoint already publishes and returns a query object. Ten
|
|
332
|
+
field types including both range forms, multi-valued selects on `Checklist`, draft-then-apply
|
|
333
|
+
by default, and `serialize` for the Unix-seconds / ISO / epoch-ms question. `DataFilter`
|
|
334
|
+
filters a client-side row set and `Filter` builds an AST; this is the third shape, and the one
|
|
335
|
+
a data-driven application needs.
|
|
336
|
+
- **`ListToolbar` — the bar above a record view.** Search, a live result count, a view switch and
|
|
337
|
+
badged tools. A tool's badge is part of its accessible name rather than a second thing beside
|
|
338
|
+
it, `setCount(null)` clears the live region during a load, and `bind()` feature-detects a
|
|
339
|
+
`TableView`/`CardView` instead of importing it.
|
|
340
|
+
- **`StatTile` / `statTile()` — the labelled metric.** Formats through the core formatters, never
|
|
341
|
+
encodes "up is good" (`deltaKind` decides the colour, not the sign), marks its sparkline
|
|
342
|
+
`aria-hidden`, and picks `<a>` / `<button>` / `<div role="group">` from the behaviour it was
|
|
343
|
+
given rather than wrapping a click handler round a div.
|
|
344
|
+
- **`Table` group and section rows.** `rowKind` and `rowKinds` render a `<th scope="colgroup">`
|
|
345
|
+
spanning every rendered cell, including the selection and reorder columns. `CardView` has had
|
|
346
|
+
`groupBy`; `Table` had nothing, while `Grid.BillingItems()` already modelled the row kind for
|
|
347
|
+
editability and simply never drew it. Sort controls are withheld while a spanning row is
|
|
348
|
+
present, because sorting a grouped table scatters its positions out of their sections.
|
|
349
|
+
- **`ActivityItem.state`** — `pending` and `failed`, for an entry rendered optimistically before
|
|
350
|
+
its request resolves and for one whose send failed. An entry that disappears on failure tells
|
|
351
|
+
the reader their message was sent when nobody was told.
|
|
352
|
+
|
|
353
|
+
### Changed
|
|
354
|
+
|
|
355
|
+
- **The move handle is no longer pointer furniture.** Since 4.3.4 the card itself is the drag
|
|
356
|
+
source, so the knob is decoration that competes with the card's content. The new
|
|
357
|
+
`moveHandle: 'keyboard' | 'always'` defaults to `keyboard`: the button stays in the DOM, in tab
|
|
358
|
+
order, and fully announced, but is clipped out of sight and out of the layout until it takes
|
|
359
|
+
focus or holds a grabbed card. `always` restores the 4.3.4 presentation, and `dragFrom: 'handle'`
|
|
360
|
+
keeps the handle visible regardless, since it is then the only thing a pointer user can grab.
|
|
361
|
+
- **An empty column now reads as a drop target.** `labels.columnEmpty` defaults to
|
|
362
|
+
"Drop a card here" in a dashed zone instead of an empty gap; `labels.columnEmpty: ''` restores
|
|
363
|
+
the previous blank column, and `renderColumnEmpty` still replaces it.
|
|
364
|
+
- **A field the card head or footer projects no longer repeats itself as a metadata row.** Set
|
|
365
|
+
`duplicate: true` on the field descriptor to show it in both places.
|
|
366
|
+
|
|
367
|
+
- **`fieldControls` accepts `{label, target}`** on `TableView`, `CardView` and `KanbanView`.
|
|
368
|
+
`true`/`false` are unchanged. The chooser's trigger can now be named, and mounted into a host
|
|
369
|
+
toolbar instead of the view's own — which is what made it usable in a translated product at
|
|
370
|
+
all.
|
|
371
|
+
- **`DialogButton.disabled`**, honoured by the constructor, `setButtons()` and per-view buttons,
|
|
372
|
+
and skipped by `autofocus`. `Sheet` inherits it. A form a client cannot render completely must
|
|
373
|
+
not be submittable, and until now the only way to show that was to reach into the rendered
|
|
374
|
+
footer.
|
|
375
|
+
- **Roughly ninety-six user-visible strings across sixteen components now route through
|
|
376
|
+
`_message()`**, which falls back to `translate()` — so installing a host translator is enough.
|
|
377
|
+
Most are `aria-label` and `title`, which is the half that does not show up in a screenshot: a
|
|
378
|
+
German application previously announced "Clear search", "Close message" and "Previous month" in
|
|
379
|
+
the middle of its own chrome, with no option to prevent it. Every English fallback is
|
|
380
|
+
byte-identical to the previous literal.
|
|
381
|
+
- **`Launcher` and `Filter` label options default to `null`** and resolve through the translator,
|
|
382
|
+
so an application that installs one and passes no labels gets a translated component. The
|
|
383
|
+
rendered words are unchanged without a translator.
|
|
384
|
+
- **`AppSidebar` visual pass.** A filled active pill with an edge marker and a weight change, so
|
|
385
|
+
nothing rests on colour alone; one spacing scale; a fixed icon gutter that collapses when no
|
|
386
|
+
item has an icon; labels that wrap and hyphenate rather than truncate; badges that survive
|
|
387
|
+
minimization as a dot with the number still in the accessible name. Options, events, methods,
|
|
388
|
+
DOM and the keyboard map are unchanged.
|
|
389
|
+
- **`NavigationBar` overflow is configurable.** `overflow: false` keeps every item at every
|
|
390
|
+
width; `overflowBelow` moves the collapse threshold; `minVisible: n` pins the first `n` items.
|
|
391
|
+
Defaults are unchanged — every item still collapses below 44 rem through the same container
|
|
392
|
+
query, with no observer installed. Collapsing all of a navigation into one button is right for
|
|
393
|
+
a top app bar and wrong for a phone bottom bar, and there was no way to say so.
|
|
394
|
+
- **A print stylesheet ships.** `styles/print.css`, imported last, releases sticky headers and
|
|
395
|
+
scroll containers, drops fills, shadows, zebra striping and focus rings, hides overlays and
|
|
396
|
+
navigation chrome, repeats table headers across pages, keeps cards and rows from breaking, and
|
|
397
|
+
prints link URLs in prose but never inside a table cell or on a button. Status badges keep
|
|
398
|
+
their colour, because there it carries meaning beside the word. An application that sets
|
|
399
|
+
`data-zx-theme="dark"` explicitly still prints dark text tokens; `auto` is unaffected.
|
|
400
|
+
|
|
401
|
+
### Fixed
|
|
402
|
+
|
|
403
|
+
- **Context-menu selection could not be cancelled.** Preventing its `select` event now suppresses
|
|
404
|
+
the item callback and native link navigation and leaves the menu open, matching MenuButton.
|
|
405
|
+
- **The keyboard move handle could take focus while staying invisible.** It revealed itself on
|
|
406
|
+
`:focus-visible`, which does not match after pointer input — so the focus a committed pointer
|
|
407
|
+
drop moves onto the handle landed on a one-pixel control. It now reveals on `:focus`, and
|
|
408
|
+
`dragFrom: 'handle'` keeps the handle visible regardless of `moveHandle`.
|
|
409
|
+
- **A literal indicator descriptor rendered nothing.** `priority: {label: 'Blocked'}` was read as
|
|
410
|
+
a record property name and resolved `undefined`.
|
|
411
|
+
- **A blank progress label produced an unnamed progressbar.** An empty or whitespace label now
|
|
412
|
+
falls back to the localized default instead of becoming `aria-label=""`.
|
|
413
|
+
- **A fractional `maxAvatars` hid every face** while the overflow chip still counted from the raw
|
|
414
|
+
option. The faces and the chip now come from one normalization.
|
|
415
|
+
- **The card identifier named itself with `aria-label` on a `<span>`**, which the generic role
|
|
416
|
+
prohibits. Identifier and indicator prefixes are visually hidden text instead.
|
|
417
|
+
- **An assignee with an image but no name rendered an unidentifiable face.** Entries without a
|
|
418
|
+
name are now dropped rather than announced as "Assigned to ".
|
|
419
|
+
- **Board rendering rebuilt the whole field-descriptor array for every axis read.** A string
|
|
420
|
+
column or lane accessor was resolved through `getFields()` — which clones every descriptor —
|
|
421
|
+
once per record per column per lane. Descriptors are now indexed once per refresh.
|
|
422
|
+
|
|
423
|
+
- **`Modal` and `Dialog` place and restore focus.** Both have always built a native `<dialog>`
|
|
424
|
+
and opened it with `showModal()`, so focus containment, page inertness, Escape and the top
|
|
425
|
+
layer were the platform's — a reading of the source that greps for a focus trap and finds
|
|
426
|
+
none draws the wrong conclusion, and one did. What was genuinely missing is now there:
|
|
427
|
+
initial focus lands on the first focusable control inside the panel rather than on the panel,
|
|
428
|
+
focus returns to the opener on every close path including the non-native presentation, and
|
|
429
|
+
`aria-modal` is set while modal. `Sheet` keeps its own trap for the non-modal case and is not
|
|
430
|
+
double-trapped. Candidates inside a `hidden`, `aria-hidden` or `inert` subtree are now skipped,
|
|
431
|
+
so a dialog whose close button is suppressed focuses its first real control instead of nothing.
|
|
432
|
+
- **`icon()` no longer throws on a name it cannot resolve.** Icon names routinely arrive from a
|
|
433
|
+
server, and one unconfigured name should not take down the screen it appears on. An
|
|
434
|
+
unresolvable inline glyph renders an empty `<svg>` of the requested size — so layout does not
|
|
435
|
+
shift — carrying `data-zx-icon-missing="<name>"`, and reports itself once per distinct name.
|
|
436
|
+
`icon(name, { strict: true })` keeps the old `RangeError` for callers that can afford to fail.
|
|
437
|
+
Font Awesome paths are unaffected: a kit resolves names in the browser, so nothing under one
|
|
438
|
+
is "unknown" here and nothing warns.
|
|
439
|
+
- **The minimized rail's flyout matches the expanded sidebar.** The visual pass in this release
|
|
440
|
+
could not reach it — the panel is portaled into a `Dropdown`, so the sidebar's descendant
|
|
441
|
+
selectors do not apply to it. It now carries the same spacing scale, icon gutter, wrapping
|
|
442
|
+
labels and active-item treatment, derived from the same tokens. Fixing it surfaced a cascade
|
|
443
|
+
bug: `app-rail.css` is imported before `dropdown.css`, so the popover's own padding had never
|
|
444
|
+
won and the panel had been rendering with the generic overlay's.
|
|
445
|
+
- **One physical-direction declaration** remained in the component tree (`table.css`), plus four
|
|
446
|
+
asymmetric box shorthands that pin an edge physically. All are logical now, and a test scans
|
|
447
|
+
for both so the state is enforced rather than accidental.
|
|
448
|
+
|
|
11
449
|
## 4.3.4 — 2026-08-31
|
|
12
450
|
|
|
13
451
|
### Added
|
package/README.md
CHANGED
|
@@ -80,6 +80,10 @@ namespaced `storage()` view that degrades to memory when the browser refuses wri
|
|
|
80
80
|
`toCsv`/`downloadBlob`/`copyToClipboard` for exporting what a table is showing.
|
|
81
81
|
|
|
82
82
|
`icon()` renders the inline SVG glyphs Zx bundles — no webfont, stylesheet, or network request.
|
|
83
|
+
They are outline icons from [Lucide](https://lucide.dev) (ISC licence; the notice ships in
|
|
84
|
+
`src/core/icons.js`): `currentColor` strokes on a 24-unit grid, about 1.2px at the default 16px.
|
|
85
|
+
`registerIcons()` adds more, either filled (`[viewBox, path]`, e.g. Font Awesome paths) or outlined
|
|
86
|
+
(`[viewBox, path, 'stroke']`, e.g. further Lucide icons).
|
|
83
87
|
Applications that want Font Awesome call `loadFontAwesome({ kit })` once, and every icon in the
|
|
84
88
|
library follows, including names Zx maps to their Font Awesome counterparts. Names can also pick a
|
|
85
89
|
renderer themselves: `'fa:user'`, `'duotone:user'`, `'kit:zeyos-notes'`, `'builtin:check'`, or a
|
|
@@ -127,6 +131,9 @@ ZeyOS binding — see `src/zeyos/modules.js`.
|
|
|
127
131
|
|
|
128
132
|
| API | Description |
|
|
129
133
|
| --- | --- |
|
|
134
|
+
| `EntityRef` | Dense linked/static entity identity with labelled metadata and injected actions. |
|
|
135
|
+
| `FileItem`, `FileList` | Durable and transient file presentation with MIME/size metadata, status, progress, downloads, and collection states. |
|
|
136
|
+
| `ActivityItem`, `ActivityList` | Chronological activity entries and grouped collections with actor, time, attachment, action, loading, and empty slots. |
|
|
130
137
|
| `Table` | Sortable/selectable table with typed transaction columns, flat-data hierarchy/treegrid projection, and opt-in cell/row editing. |
|
|
131
138
|
| `TableView` | Record-oriented Table composition with shared fields, portable state, column visibility/order, sorting, and selection. |
|
|
132
139
|
| `CardView` | Responsive record cards with configurable fields, safe preview media, grouping, actions, sorting, and selection. |
|
|
@@ -135,6 +142,8 @@ ZeyOS binding — see `src/zeyos/modules.js`.
|
|
|
135
142
|
| `Chart`, `ChartJsAdapter` | Accessible engine-neutral chart host and explicitly injected Chart.js adapter. |
|
|
136
143
|
| `Calendar` | Agenda/day/week/month/year scheduling with timed collisions, spanning events, range selection, and configurable optimistic drag/resize editing. |
|
|
137
144
|
| `DataFilter` | Declarative select, text, and custom filters for client-side row sets. |
|
|
145
|
+
| `FilterPanel` | Typed filter form built from a server's own field metadata, drafted then applied. |
|
|
146
|
+
| `ListToolbar` | Search, result count, view switch, and badged tools above a record view. |
|
|
138
147
|
| `TreeView` | APG tree with lazy children, filtering, and tri-state checkboxes. |
|
|
139
148
|
| `Finder` | Miller-columns hierarchy browser with an optional preview pane. |
|
|
140
149
|
| `Pagination` | Page, page-size, and load-more pager, with the pure `paginationRange()` helper. |
|
|
@@ -146,6 +155,7 @@ ZeyOS binding — see `src/zeyos/modules.js`.
|
|
|
146
155
|
| `Field` | Label, description, validation state, and adapter-backed form control. |
|
|
147
156
|
| `Fieldset` | Native fieldset that owns and coordinates fields. |
|
|
148
157
|
| `Form` | Form composition, values, validation, highlighting, and actions. |
|
|
158
|
+
| `CodeEditor` | Text-safe structured-text/source editor with native undo, Tab indentation, and position feedback. |
|
|
149
159
|
| `Questionnaire` | Guided one-question-at-a-time flow: branching, path-aware progress, review. |
|
|
150
160
|
| `ValueList` | Validated, sortable tag/chip editor. |
|
|
151
161
|
| `MultiValueEditor` | Ordered editable rows with add, remove, and move controls. |
|
|
@@ -160,6 +170,7 @@ ZeyOS binding — see `src/zeyos/modules.js`.
|
|
|
160
170
|
| `Avatar` | Fixed-size user image with initials fallback and optional presence. |
|
|
161
171
|
| `Groupbox` | Collapsible section backed by native `<details>`. |
|
|
162
172
|
| `Card` | Semantic content/record surface with media, native title link, actions, and footer. |
|
|
173
|
+
| `StatTile`, `statTile()` | Labelled metric with optional delta, sparkline, and loading state. |
|
|
163
174
|
| `Aurora` | One- to four-colour ambient canvas light; chrome, raised content, and overlays respond through shared material tokens. |
|
|
164
175
|
| `Launcher` | Cmd/Ctrl+K application and record launcher with ranked local items and abortable grouped sources. |
|
|
165
176
|
| `Panel` | Framed, optionally collapsible section with a footer. |
|
|
@@ -226,13 +237,13 @@ moduleColor('invoices'); // '#535494'
|
|
|
226
237
|
name, identity colour, label, and a stock Font Awesome fallback. The `--zx-module-*` CSS custom
|
|
227
238
|
properties are generated from that file, so CSS and JavaScript cannot disagree about a colour.
|
|
228
239
|
|
|
229
|
-
## Themes
|
|
240
|
+
## Themes
|
|
230
241
|
|
|
231
242
|
Load `zx.css` once. Zx components consume semantic `--zx-*` tokens and inherit their values from
|
|
232
|
-
the document. Select a built-in theme
|
|
243
|
+
the document. Select a built-in theme on any ancestor (normally `<html>`):
|
|
233
244
|
|
|
234
245
|
```html
|
|
235
|
-
<html data-zx-theme="dark"
|
|
246
|
+
<html data-zx-theme="dark">
|
|
236
247
|
```
|
|
237
248
|
|
|
238
249
|
Top-layer menus, dialogs, tooltips, launchers, and toast regions stay under the nearest Zx theme
|
|
@@ -240,10 +251,22 @@ scope in the DOM, so a theme or product-token override on a nested application s
|
|
|
240
251
|
to its overlays. Pass the optional `scope` context to Modal, Dialog, Sheet, Launcher, or static
|
|
241
252
|
Message calls when the opener is not inside the intended scope.
|
|
242
253
|
|
|
243
|
-
Theme values are `light`, `dark`, and `auto
|
|
244
|
-
|
|
254
|
+
Theme values are `light`, `dark`, and `auto`. `auto` follows the operating-system color
|
|
255
|
+
preference.
|
|
245
256
|
|
|
246
|
-
|
|
257
|
+
There is one geometry. Spacing steps are multiples of `--zx-space-unit` (4px:
|
|
258
|
+
4, 8, 12, 16, 20, 24, 32, 40), radius steps are fractions of `--zx-radius` (4px: 2, 3, 4, 6), and
|
|
259
|
+
controls are `--zx-control-height` (30px) tall. To tighten or loosen an application — or one
|
|
260
|
+
region of it — override those tokens rather than switching a mode:
|
|
261
|
+
|
|
262
|
+
```css
|
|
263
|
+
:root {
|
|
264
|
+
--zx-space-unit: 3.5px;
|
|
265
|
+
--zx-control-height: 28px;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
A second attribute picks the **accent**, orthogonally to the theme:
|
|
247
270
|
|
|
248
271
|
```html
|
|
249
272
|
<html data-zx-theme="dark" data-zx-preset="ocean">
|
|
@@ -265,6 +288,8 @@ through, so a preset rethemes light, dark, and auto at once:
|
|
|
265
288
|
|
|
266
289
|
Light surfaces take the 600 and 700 stops, dark ones take 300, 400, and 500 — so keep 600 legible
|
|
267
290
|
against white and 400 against near-black, and `--zx-color-on-accent` stays correct in both. The
|
|
291
|
+
primary button is the exception on purpose: `--zx-color-accent-solid` is the 600 stop with white
|
|
292
|
+
ink in both themes, so the one solid accent on a screen never turns into a bright slab in dark. The
|
|
268
293
|
[theme studio](https://zx.zeyos.com/theme.html) renders every component family under a live theme and
|
|
269
294
|
exports the result.
|
|
270
295
|
|
|
@@ -285,7 +310,20 @@ Anything beyond the accent is a semantic token override, without reaching into c
|
|
|
285
310
|
|
|
286
311
|
Prefer semantic tokens such as `--zx-color-*`, `--zx-control-*`, `--zx-space-*`,
|
|
287
312
|
`--zx-radius-*`, and `--zx-text-*`. Palette tokens are implementation details and should not be
|
|
288
|
-
used by application or component CSS.
|
|
313
|
+
used by application or component CSS. A few roles carry most of the visual language:
|
|
314
|
+
|
|
315
|
+
- `--zx-color-bg-chrome` for navigation and inspector columns beside the `--zx-color-bg-surface`
|
|
316
|
+
canvas, and `--zx-color-border-subtle` for dividers inside them — tone separates, lines only
|
|
317
|
+
where tone cannot.
|
|
318
|
+
- `--zx-color-bg-current` (neutral) for where you are, `--zx-color-bg-selected` (accent tint) for
|
|
319
|
+
what you picked.
|
|
320
|
+
- `--zx-color-text-muted` for secondary text and `--zx-color-text-subtle` for icons and meta.
|
|
321
|
+
- `--zx-color-tone-<hue>-bg` / `-fg` (blue, teal, green, amber, orange, red, pink, violet, slate)
|
|
322
|
+
for categorical colour — tags, avatars, icon tiles — and `--zx-color-chart-1` … `-8` for chart
|
|
323
|
+
series. Neither is the accent or a status colour; `success` is a yellow-green of its own.
|
|
324
|
+
|
|
325
|
+
Add `data-zx-fields="quiet"` to a property panel and its native fields show no border or fill until
|
|
326
|
+
hovered or focused.
|
|
289
327
|
|
|
290
328
|
## Browser support
|
|
291
329
|
|
|
@@ -304,9 +342,10 @@ npm install
|
|
|
304
342
|
npm run serve
|
|
305
343
|
```
|
|
306
344
|
|
|
307
|
-
Open <http://127.0.0.1:8321/website/docs.html> for the documentation — getting started, every
|
|
308
|
-
component with a live demo and its JavaScript source
|
|
309
|
-
|
|
345
|
+
Open <http://127.0.0.1:8321/website/docs.html> for the documentation — getting started, and every
|
|
346
|
+
component with a live demo and its JavaScript source — and
|
|
347
|
+
<http://127.0.0.1:8321/website/layouts.html> for the gallery of application layouts. Also
|
|
348
|
+
available: <http://127.0.0.1:8321/tests/smoke/smoke.html> for source-module smoke tests, or build first and open <http://127.0.0.1:8321/tests/smoke/smoke-dist.html> for
|
|
310
349
|
classic-script distribution tests.
|
|
311
350
|
|
|
312
351
|
```sh
|