@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.
- package/CHANGELOG.md +283 -0
- package/README.md +42 -10
- package/dist/types/components/activity-list/activity-list.d.ts +22 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +5 -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 +15 -0
- 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 +6 -17
- 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 +46 -6
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/entity-ref/entity-ref.d.ts +2 -2
- 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 +34 -6
- package/dist/types/components/form/form.d.ts +12 -1
- package/dist/types/components/kanban-view/kanban-card.d.ts +8 -0
- package/dist/types/components/launcher/launcher.d.ts +260 -15
- package/dist/types/components/list-toolbar/list-toolbar.d.ts +1 -1
- package/dist/types/components/menu-button/menu-button.d.ts +33 -5
- package/dist/types/components/message/message.d.ts +119 -17
- package/dist/types/components/modal/modal.d.ts +13 -2
- 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 +11 -3
- package/dist/types/components/stat-tile/stat-tile.d.ts +16 -5
- package/dist/types/components/tabbox/tabbox.d.ts +9 -0
- package/dist/types/components/table/table.d.ts +46 -1
- package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
- package/dist/types/components/tree/tree.d.ts +13 -0
- package/dist/types/core/breakpoint.d.ts +1 -1
- package/dist/types/core/icons.d.ts +23 -25
- 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 +5 -3
- 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 +1621 -443
- package/dist/zx-zeyos.esm.min.js +53 -5
- package/dist/zx.css +1411 -660
- package/dist/zx.esm.js +1976 -703
- package/dist/zx.esm.min.js +56 -8
- package/dist/zx.global.js +1978 -705
- package/dist/zx.global.min.js +56 -8
- package/dist/zx.min.css +1 -1
- package/docs/api.json +219 -34
- package/docs/llms.md +472 -110
- package/docs/llms.txt +3 -3
- package/package.json +1 -1
- package/src/components/account-menu/account-menu.css +35 -10
- package/src/components/activity-item/activity-item.css +1 -1
- package/src/components/activity-item/activity-item.js +3 -0
- package/src/components/activity-list/activity-list.css +38 -3
- package/src/components/activity-list/activity-list.js +34 -0
- package/src/components/app-icon/app-icon.css +1 -1
- package/src/components/app-rail/app-rail.css +40 -79
- package/src/components/app-sidebar/app-sidebar.css +109 -174
- package/src/components/app-sidebar/app-sidebar.js +21 -6
- 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 +67 -9
- package/src/components/button/button.js +38 -0
- package/src/components/calendar/calendar.css +46 -46
- package/src/components/card/card.css +2 -2
- package/src/components/card-view/card-view.css +9 -7
- 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 +6 -5
- package/src/components/code-editor/code-editor.js +19 -1
- package/src/components/context-menu/context-menu.css +9 -4
- 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-range-picker.css +3 -3
- package/src/components/date-picker/time-picker.css +1 -1
- 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 +99 -17
- package/src/components/dropdown/dropdown.css +1 -1
- package/src/components/dropdown/dropdown.js +5 -3
- package/src/components/empty-state/empty-state.css +2 -2
- package/src/components/entity-ref/entity-ref.css +1 -1
- package/src/components/entity-ref/entity-ref.js +1 -1
- 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.js +144 -10
- package/src/components/filter/filter.js +7 -3
- package/src/components/filter-panel/filter-panel.css +1 -1
- 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 +11 -3
- package/src/components/kanban-view/kanban-view.css +39 -15
- package/src/components/kanban-view/kanban-view.js +4 -4
- package/src/components/launcher/launcher.css +107 -25
- package/src/components/launcher/launcher.js +503 -41
- package/src/components/list-toolbar/list-toolbar.css +13 -8
- package/src/components/list-toolbar/list-toolbar.js +1 -1
- package/src/components/master-panel/master-panel.css +2 -0
- package/src/components/menu-button/menu-button.css +9 -4
- package/src/components/menu-button/menu-button.js +65 -9
- package/src/components/message/message.css +33 -3
- package/src/components/message/message.js +217 -15
- package/src/components/modal/modal.js +18 -3
- package/src/components/navigation-bar/navigation-bar.css +18 -9
- 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/rating/rating.css +7 -0
- package/src/components/select/color.js +22 -0
- package/src/components/select/field-adapter.js +2 -0
- package/src/components/select/glyphs.js +165 -0
- package/src/components/select/select.css +138 -45
- package/src/components/select/select.js +83 -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 +4 -1
- package/src/components/stat-tile/stat-tile.css +41 -46
- package/src/components/stat-tile/stat-tile.js +17 -6
- package/src/components/tabbox/tabbox.css +32 -27
- package/src/components/tabbox/tabbox.js +5 -1
- package/src/components/table/table.css +104 -29
- package/src/components/table/table.js +90 -16
- package/src/components/tag-picker/tag-picker.css +83 -5
- package/src/components/tag-picker/tag-picker.js +25 -8
- package/src/components/timebox/timebox.css +22 -2
- 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/view/record-view.js +1 -1
- package/src/core/breakpoint.js +1 -1
- package/src/core/icons.js +193 -60
- package/src/core/motion.js +147 -0
- package/src/core/overlay-host.js +21 -2
- package/src/index.js +5 -3
- package/src/internal/app-rail.js +1 -2
- 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/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 +0 -1
- package/styles/tokens/density.css +0 -9
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { h } from '../../core/dom.js';
|
|
2
|
+
import { icon } from '../../core/icons.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The shapes a workflow-status glyph can take. Each status reads by shape first and colour
|
|
6
|
+
* second, so the set stays legible to readers who do not see the colour.
|
|
7
|
+
* @typedef {'dotted'|'ring'|'progress'|'review'|'ready'|'waiting'|'done'|'canceled'|'duplicate'} StatusIndicator
|
|
8
|
+
*/
|
|
9
|
+
/** @typedef {'muted'|'neutral'|'warning'|'info'|'accent'|'success'|'danger'} StatusTone */
|
|
10
|
+
/**
|
|
11
|
+
* The built-in workflow statuses. `review` and `cancelled` are accepted as spellings of
|
|
12
|
+
* `in-review` and `canceled`.
|
|
13
|
+
* @typedef {'backlog'|'todo'|'in-progress'|'in-review'|'review'|'ready'|'waiting'|'done'|'canceled'|'cancelled'|'duplicate'} StatusId
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} StatusIconOptions
|
|
17
|
+
* @property {StatusIndicator} [indicator] Shape, overriding the status's own.
|
|
18
|
+
* @property {StatusTone} [tone] Colour, overriding the status's own.
|
|
19
|
+
* @property {string|null} [label=null] Accessible name. Without one the glyph is decorative
|
|
20
|
+
* (`aria-hidden`) and must sit beside text, or inside a control with a tooltip, that says the
|
|
21
|
+
* status.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} PriorityIconOptions
|
|
25
|
+
* @property {string|null} [label=null] Accessible name. Without one the glyph is decorative
|
|
26
|
+
* (`aria-hidden`) and must sit beside text, or inside a control with a tooltip, that says the
|
|
27
|
+
* priority.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** Every shape `statusIcon()` draws. */
|
|
31
|
+
export const STATUS_INDICATORS = Object.freeze([
|
|
32
|
+
'dotted', 'ring', 'progress', 'review', 'ready', 'waiting', 'done', 'canceled', 'duplicate'
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
/** Every colour a status glyph takes, from the semantic set. */
|
|
36
|
+
export const STATUS_TONES = Object.freeze([
|
|
37
|
+
'muted', 'neutral', 'warning', 'info', 'accent', 'success', 'danger'
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The built-in statuses in workflow order, as `[id, message key, English name, indicator, tone]`.
|
|
42
|
+
* `Select.status()` lists them; `statusIcon()` draws them.
|
|
43
|
+
*/
|
|
44
|
+
export const DEFAULT_STATUSES = Object.freeze([
|
|
45
|
+
['backlog', 'status.backlog', 'Backlog', 'dotted', 'muted'],
|
|
46
|
+
['todo', 'status.todo', 'Todo', 'ring', 'neutral'],
|
|
47
|
+
['in-progress', 'status.inProgress', 'In Progress', 'progress', 'warning'],
|
|
48
|
+
['in-review', 'status.inReview', 'In Review', 'review', 'info'],
|
|
49
|
+
['ready', 'status.ready', 'Ready to Merge', 'ready', 'accent'],
|
|
50
|
+
['waiting', 'status.waiting', 'Waiting for feedback', 'waiting', 'warning'],
|
|
51
|
+
['done', 'status.done', 'Done', 'done', 'info'],
|
|
52
|
+
['canceled', 'status.canceled', 'Canceled', 'canceled', 'muted'],
|
|
53
|
+
['duplicate', 'status.duplicate', 'Duplicate', 'duplicate', 'muted']
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
/** Other spellings of the built-in status ids. */
|
|
57
|
+
const STATUS_ALIASES = Object.freeze({ review: 'in-review', cancelled: 'canceled' });
|
|
58
|
+
|
|
59
|
+
/** The top priority level, the one coloured level: a danger square with an exclamation mark. */
|
|
60
|
+
export const PRIORITY_URGENT = 4;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the shape and colour of a status glyph.
|
|
64
|
+
*
|
|
65
|
+
* A status is a built-in id (or one of its other spellings), or a status item of the kind
|
|
66
|
+
* `Select.status({items})` takes, whose own `indicator` and `tone` win over the built-in status
|
|
67
|
+
* its `ID` names. Options win over both. An unknown shape falls back to the empty ring and an
|
|
68
|
+
* unknown colour to muted, as `Select.status()` does with a custom item.
|
|
69
|
+
* @param {StatusId|string|{ID?: unknown, id?: unknown, indicator?: unknown, tone?: unknown}|null|undefined} status
|
|
70
|
+
* @param {StatusIconOptions} [options={}] Overrides.
|
|
71
|
+
* @returns {{indicator: StatusIndicator, tone: StatusTone}}
|
|
72
|
+
*/
|
|
73
|
+
export function resolveStatusGlyph(status, options = {}) {
|
|
74
|
+
const item = status && typeof status === 'object' ? status : null;
|
|
75
|
+
const id = normalizeStatusId(item ? (item.ID ?? item.id) : status);
|
|
76
|
+
const preset = DEFAULT_STATUSES.find(([key]) => key === id);
|
|
77
|
+
const indicator = String(options.indicator ?? item?.indicator ?? preset?.[3] ?? 'ring');
|
|
78
|
+
const tone = String(options.tone ?? item?.tone ?? preset?.[4] ?? 'muted');
|
|
79
|
+
return {
|
|
80
|
+
indicator: /** @type {StatusIndicator} */ (STATUS_INDICATORS.includes(indicator) ? indicator : 'ring'),
|
|
81
|
+
tone: /** @type {StatusTone} */ (STATUS_TONES.includes(tone) ? tone : 'muted')
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Maps a status id to its built-in spelling: trimmed, lower-cased, and `review` / `cancelled`
|
|
87
|
+
* read as `in-review` / `canceled`.
|
|
88
|
+
* @param {unknown} id Status id.
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
export function normalizeStatusId(id) {
|
|
92
|
+
const key = String(id ?? '').trim().toLowerCase();
|
|
93
|
+
return STATUS_ALIASES[key] ?? key;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Settles a priority level: an integer from 0 (lowest) to 4 (highest), or `null` for no priority.
|
|
98
|
+
* Out-of-range numbers clamp; anything that is not a number reads as 0.
|
|
99
|
+
* @param {unknown} level Priority level.
|
|
100
|
+
* @returns {number|null}
|
|
101
|
+
*/
|
|
102
|
+
export function normalizePriorityLevel(level) {
|
|
103
|
+
if (level === null || level === undefined || level === '') return null;
|
|
104
|
+
return Math.max(0, Math.min(PRIORITY_URGENT, Math.trunc(Number(level) || 0)));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Draws the workflow-status glyph `Select.status()` shows, for a list row, a board column, a
|
|
109
|
+
* filter chip, or a heading — so every place a status appears reads as the picker that changes it.
|
|
110
|
+
*
|
|
111
|
+
* Built-in statuses: `backlog` (dotted ring), `todo` (empty ring), `in-progress` (ring with a
|
|
112
|
+
* centre dot), `in-review` (half filled; also `review`), `ready` (a third filled), `waiting` (two
|
|
113
|
+
* thirds filled), `done` (filled, with a check), `canceled` (filled, with a cross; also
|
|
114
|
+
* `cancelled`), and `duplicate` (ring with a slash). Colour only repeats what the shape says.
|
|
115
|
+
* @param {StatusId|string|{ID?: unknown, indicator?: unknown, tone?: unknown}} status Built-in id,
|
|
116
|
+
* or a status item with its own `indicator` and `tone`.
|
|
117
|
+
* @param {StatusIconOptions} [options={}] Shape, colour, and accessible-name overrides.
|
|
118
|
+
* @returns {HTMLSpanElement} A `.zx-status-icon` element, decorative unless `label` is given.
|
|
119
|
+
*/
|
|
120
|
+
export function statusIcon(status, options = {}) {
|
|
121
|
+
const { indicator, tone } = resolveStatusGlyph(status, options ?? {});
|
|
122
|
+
const marker = /** @type {HTMLSpanElement} */ (h('span', {
|
|
123
|
+
class: 'zx-status-icon',
|
|
124
|
+
dataset: { indicator, tone }
|
|
125
|
+
}));
|
|
126
|
+
if (indicator === 'done') marker.append(icon('check', { size: 8 }));
|
|
127
|
+
if (indicator === 'canceled') marker.append(icon('x', { size: 7 }));
|
|
128
|
+
return name(marker, options?.label);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Draws the priority glyph `Select.priority()` shows. Levels 0–3 are four signal bars in muted
|
|
133
|
+
* ink, filled up to the level; level 4, the highest, is a filled danger square whose "!" the
|
|
134
|
+
* stylesheet draws, so it never joins the text beside it; no priority (`null`) is a row of dashes.
|
|
135
|
+
* @param {number|null} level Priority level, 0 (lowest) to 4 (highest), or `null` for none.
|
|
136
|
+
* @param {PriorityIconOptions} [options={}] Accessible-name option.
|
|
137
|
+
* @returns {HTMLSpanElement} A `.zx-priority-icon` element, decorative unless `label` is given.
|
|
138
|
+
*/
|
|
139
|
+
export function priorityIcon(level, options = {}) {
|
|
140
|
+
const normalized = normalizePriorityLevel(level);
|
|
141
|
+
const glyph = /** @type {HTMLSpanElement} */ (h('span', {
|
|
142
|
+
class: 'zx-priority-icon',
|
|
143
|
+
dataset: { level: normalized === null ? 'none' : normalized }
|
|
144
|
+
}, normalized === PRIORITY_URGENT ? null : Array.from({ length: PRIORITY_URGENT }, (_, index) => h('span', {
|
|
145
|
+
dataset: { filled: String(normalized !== null && index <= normalized) }
|
|
146
|
+
}))));
|
|
147
|
+
return name(glyph, options?.label);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Makes a glyph an image with an accessible name, or hides it from assistive technology.
|
|
152
|
+
* @param {HTMLSpanElement} glyph Glyph element.
|
|
153
|
+
* @param {unknown} label Accessible name, if any.
|
|
154
|
+
* @returns {HTMLSpanElement}
|
|
155
|
+
*/
|
|
156
|
+
function name(glyph, label) {
|
|
157
|
+
const text = label == null ? '' : String(label).trim();
|
|
158
|
+
if (text) {
|
|
159
|
+
glyph.setAttribute('role', 'img');
|
|
160
|
+
glyph.setAttribute('aria-label', text);
|
|
161
|
+
} else {
|
|
162
|
+
glyph.setAttribute('aria-hidden', 'true');
|
|
163
|
+
}
|
|
164
|
+
return glyph;
|
|
165
|
+
}
|
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
padding-inline-start: var(--zx-space-2) !important;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
.
|
|
33
|
+
/* The ring follows keyboard focus. A text input matches :focus-visible on a click as well, so the
|
|
34
|
+
component marks a pointer focus on a read-only input (`data-focus-origin="pointer"`) and the ring
|
|
35
|
+
waits for the first key. An editable input keeps it on click, as any text field does. */
|
|
36
|
+
.zx-select:not([data-focus-origin="pointer"]) .zx-select__control:has(.zx-select__input:focus-visible) {
|
|
34
37
|
box-shadow: var(--zx-focus-ring);
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -85,9 +88,17 @@
|
|
|
85
88
|
border-radius: var(--zx-radius-full);
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
/* Disabled reads the way a disabled Field does: text and frame fade together, nothing else
|
|
92
|
+
changes. Inside a disabled Field the field has already faded, so the Select does not again. */
|
|
93
|
+
.zx-select[aria-disabled="true"] {
|
|
94
|
+
opacity: 0.65;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.zx-field[data-disabled="true"] .zx-select[aria-disabled="true"] {
|
|
98
|
+
opacity: 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
88
101
|
.zx-select[aria-disabled="true"] .zx-select__control {
|
|
89
|
-
background: var(--zx-color-bg-page);
|
|
90
|
-
color: var(--zx-color-text-muted);
|
|
91
102
|
cursor: default;
|
|
92
103
|
}
|
|
93
104
|
|
|
@@ -97,7 +108,7 @@
|
|
|
97
108
|
max-inline-size: calc(100vw - var(--zx-space-4));
|
|
98
109
|
overflow: hidden;
|
|
99
110
|
border: 1px solid var(--zx-color-overlay-border);
|
|
100
|
-
border-radius: var(--zx-radius-
|
|
111
|
+
border-radius: var(--zx-radius-lg);
|
|
101
112
|
background-color: var(--zx-color-overlay-surface);
|
|
102
113
|
background-image: var(--zx-overlay-surface-image);
|
|
103
114
|
background-clip: padding-box;
|
|
@@ -118,10 +129,12 @@
|
|
|
118
129
|
display: flex;
|
|
119
130
|
align-items: center;
|
|
120
131
|
gap: var(--zx-space-2);
|
|
121
|
-
|
|
132
|
+
/* The same row as a menu item: a little under a control, the smallest radius. */
|
|
133
|
+
min-block-size: calc(var(--zx-control-height) - 2px);
|
|
122
134
|
border-radius: var(--zx-radius-sm);
|
|
123
135
|
cursor: default;
|
|
124
|
-
padding: var(--zx-space-1) var(--zx-
|
|
136
|
+
padding: var(--zx-space-1) var(--zx-space-2);
|
|
137
|
+
line-height: 1.35;
|
|
125
138
|
}
|
|
126
139
|
|
|
127
140
|
.zx-select__option-content {
|
|
@@ -137,6 +150,8 @@
|
|
|
137
150
|
background: var(--zx-color-overlay-hover);
|
|
138
151
|
}
|
|
139
152
|
|
|
153
|
+
/* The highlighted option (keyboard or pointer) is a neutral step; a chosen option is a pick and
|
|
154
|
+
keeps the accent tint and its check mark. */
|
|
140
155
|
.zx-select__option[aria-selected="true"] {
|
|
141
156
|
background: var(--zx-color-overlay-selected);
|
|
142
157
|
}
|
|
@@ -146,6 +161,7 @@
|
|
|
146
161
|
color: var(--zx-color-accent);
|
|
147
162
|
}
|
|
148
163
|
|
|
164
|
+
/* A caption for the options under it, in sentence case: quieter than the options, never louder. */
|
|
149
165
|
.zx-select__group {
|
|
150
166
|
position: sticky;
|
|
151
167
|
z-index: 1;
|
|
@@ -153,10 +169,8 @@
|
|
|
153
169
|
background: var(--zx-color-overlay-scrim);
|
|
154
170
|
color: var(--zx-color-text-muted);
|
|
155
171
|
font-size: var(--zx-text-xs);
|
|
156
|
-
font-weight:
|
|
157
|
-
|
|
158
|
-
padding: var(--zx-space-2) var(--zx-control-pad-x) var(--zx-space-1);
|
|
159
|
-
text-transform: uppercase;
|
|
172
|
+
font-weight: var(--zx-weight-semibold);
|
|
173
|
+
padding: var(--zx-space-1) var(--zx-space-2);
|
|
160
174
|
}
|
|
161
175
|
|
|
162
176
|
@media (prefers-reduced-transparency: reduce) {
|
|
@@ -175,13 +189,13 @@
|
|
|
175
189
|
|
|
176
190
|
.zx-select__separator {
|
|
177
191
|
block-size: 1px;
|
|
178
|
-
margin: var(--zx-space-1) var(--zx-
|
|
192
|
+
margin: var(--zx-space-1) var(--zx-space-2);
|
|
179
193
|
background: var(--zx-color-overlay-divider);
|
|
180
194
|
}
|
|
181
195
|
|
|
182
196
|
.zx-select__empty {
|
|
183
197
|
color: var(--zx-color-text-muted);
|
|
184
|
-
padding: var(--zx-space-3) var(--zx-
|
|
198
|
+
padding: var(--zx-space-3) var(--zx-space-2);
|
|
185
199
|
text-align: center;
|
|
186
200
|
}
|
|
187
201
|
|
|
@@ -191,30 +205,59 @@
|
|
|
191
205
|
gap: var(--zx-space-2);
|
|
192
206
|
}
|
|
193
207
|
|
|
194
|
-
.
|
|
208
|
+
/* The priority glyph — `priorityIcon()`, and the one Select.priority() draws, which also carries
|
|
209
|
+
`.zx-select__priority-icon`. Priority is read by height, not by hue: four signal bars, the filled
|
|
210
|
+
ones in muted ink and the rest a step quieter. Only the top level, the one that needs attention,
|
|
211
|
+
is coloured — a danger square with an exclamation mark. "No priority" is a row of dashes. Every
|
|
212
|
+
glyph takes the same box, so the labels after them line up. */
|
|
213
|
+
.zx-priority-icon {
|
|
195
214
|
display: inline-flex;
|
|
196
|
-
gap: 2px;
|
|
197
215
|
flex: none;
|
|
198
|
-
|
|
216
|
+
vertical-align: middle;
|
|
217
|
+
align-items: flex-end;
|
|
218
|
+
gap: 1px;
|
|
219
|
+
box-sizing: border-box;
|
|
220
|
+
inline-size: 15px;
|
|
221
|
+
block-size: 14px;
|
|
222
|
+
padding-block: 1px;
|
|
223
|
+
color: var(--zx-color-text-muted);
|
|
199
224
|
}
|
|
200
225
|
|
|
201
|
-
.zx-
|
|
202
|
-
inline-size:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
border-radius: 2px;
|
|
226
|
+
.zx-priority-icon > span {
|
|
227
|
+
inline-size: 3px;
|
|
228
|
+
border-radius: 1px;
|
|
229
|
+
background: var(--zx-color-border-strong);
|
|
206
230
|
}
|
|
207
231
|
|
|
208
|
-
.zx-
|
|
209
|
-
.zx-
|
|
210
|
-
.zx-
|
|
211
|
-
|
|
232
|
+
.zx-priority-icon > span:nth-child(1) { block-size: 25%; }
|
|
233
|
+
.zx-priority-icon > span:nth-child(2) { block-size: 50%; }
|
|
234
|
+
.zx-priority-icon > span:nth-child(3) { block-size: 75%; }
|
|
235
|
+
.zx-priority-icon > span:nth-child(4) { block-size: 100%; }
|
|
236
|
+
.zx-priority-icon > span[data-filled="true"] { background: currentColor; }
|
|
237
|
+
|
|
238
|
+
.zx-priority-icon[data-level="none"] { align-items: center; }
|
|
239
|
+
.zx-priority-icon[data-level="none"] > span {
|
|
240
|
+
block-size: 2px;
|
|
241
|
+
background: currentColor;
|
|
212
242
|
}
|
|
213
|
-
|
|
214
|
-
.zx-
|
|
215
|
-
|
|
243
|
+
|
|
244
|
+
.zx-priority-icon[data-level="4"] {
|
|
245
|
+
align-items: center;
|
|
246
|
+
justify-content: center;
|
|
247
|
+
inline-size: 14px;
|
|
248
|
+
margin-inline-end: 1px;
|
|
249
|
+
padding: 0;
|
|
250
|
+
border-radius: var(--zx-radius-sm);
|
|
251
|
+
background: var(--zx-color-danger);
|
|
252
|
+
color: var(--zx-color-on-accent);
|
|
253
|
+
font-size: 11px;
|
|
254
|
+
font-weight: var(--zx-weight-semibold);
|
|
255
|
+
line-height: 1;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.zx-priority-icon[data-level="4"]::before {
|
|
259
|
+
content: "!";
|
|
216
260
|
}
|
|
217
|
-
.zx-select__priority-icon[data-level="4"] { color: var(--zx-color-danger); }
|
|
218
261
|
|
|
219
262
|
.zx-select__status {
|
|
220
263
|
display: grid;
|
|
@@ -223,13 +266,20 @@
|
|
|
223
266
|
gap: var(--zx-space-2);
|
|
224
267
|
}
|
|
225
268
|
|
|
269
|
+
/* An entity without a colour of its own is a neutral tile with muted ink; one with a colour is
|
|
270
|
+
filled with it and drawn in the inverse text colour. */
|
|
226
271
|
.zx-select__entity-glyph {
|
|
227
272
|
display: inline-grid;
|
|
228
273
|
place-items: center;
|
|
229
274
|
inline-size: 20px;
|
|
230
275
|
block-size: 20px;
|
|
231
276
|
border-radius: var(--zx-radius-sm);
|
|
232
|
-
background: var(--zx-
|
|
277
|
+
background: var(--zx-color-bg-muted);
|
|
278
|
+
color: var(--zx-color-text-muted);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.zx-select__entity-glyph[style*="--zx-select-entity-color"] {
|
|
282
|
+
background: var(--zx-select-entity-color);
|
|
233
283
|
color: var(--zx-color-text-invert);
|
|
234
284
|
}
|
|
235
285
|
|
|
@@ -256,10 +306,14 @@
|
|
|
256
306
|
font-size: var(--zx-text-xs);
|
|
257
307
|
}
|
|
258
308
|
|
|
259
|
-
|
|
309
|
+
/* The workflow-status glyph — `statusIcon()`, and the one Select.status() draws, which also carries
|
|
310
|
+
`.zx-select__status-indicator`. Each status is a shape first and a colour second. */
|
|
311
|
+
.zx-status-icon {
|
|
260
312
|
position: relative;
|
|
261
313
|
display: inline-grid;
|
|
262
314
|
place-items: center;
|
|
315
|
+
box-sizing: border-box;
|
|
316
|
+
vertical-align: middle;
|
|
263
317
|
inline-size: 14px;
|
|
264
318
|
block-size: 14px;
|
|
265
319
|
flex: none;
|
|
@@ -268,37 +322,37 @@
|
|
|
268
322
|
color: var(--zx-color-text-muted);
|
|
269
323
|
}
|
|
270
324
|
|
|
271
|
-
.zx-
|
|
272
|
-
.zx-
|
|
273
|
-
.zx-
|
|
274
|
-
.zx-
|
|
275
|
-
.zx-
|
|
276
|
-
.zx-
|
|
325
|
+
.zx-status-icon[data-tone="neutral"] { color: var(--zx-color-border-strong); }
|
|
326
|
+
.zx-status-icon[data-tone="warning"] { color: var(--zx-color-warning); }
|
|
327
|
+
.zx-status-icon[data-tone="info"] { color: var(--zx-color-info); }
|
|
328
|
+
.zx-status-icon[data-tone="accent"] { color: var(--zx-color-accent); }
|
|
329
|
+
.zx-status-icon[data-tone="success"] { color: var(--zx-color-success); }
|
|
330
|
+
.zx-status-icon[data-tone="danger"] { color: var(--zx-color-danger); }
|
|
277
331
|
|
|
278
|
-
.zx-
|
|
279
|
-
.zx-
|
|
332
|
+
.zx-status-icon[data-indicator="dotted"] { border-style: dotted; }
|
|
333
|
+
.zx-status-icon[data-indicator="progress"]::after {
|
|
280
334
|
content: "";
|
|
281
335
|
inline-size: 4px;
|
|
282
336
|
block-size: 4px;
|
|
283
337
|
border-radius: inherit;
|
|
284
338
|
background: currentColor;
|
|
285
339
|
}
|
|
286
|
-
.zx-
|
|
340
|
+
.zx-status-icon[data-indicator="review"] {
|
|
287
341
|
background: linear-gradient(90deg, currentColor 50%, transparent 50%);
|
|
288
342
|
}
|
|
289
|
-
.zx-
|
|
343
|
+
.zx-status-icon[data-indicator="ready"] {
|
|
290
344
|
background: conic-gradient(currentColor 0 35%, transparent 35% 100%);
|
|
291
345
|
}
|
|
292
|
-
.zx-
|
|
346
|
+
.zx-status-icon[data-indicator="waiting"] {
|
|
293
347
|
background: conic-gradient(currentColor 0 70%, transparent 70% 100%);
|
|
294
348
|
}
|
|
295
|
-
.zx-
|
|
349
|
+
.zx-status-icon:is([data-indicator="done"], [data-indicator="canceled"]) {
|
|
296
350
|
background: currentColor;
|
|
297
351
|
}
|
|
298
|
-
.zx-
|
|
352
|
+
.zx-status-icon:is([data-indicator="done"], [data-indicator="canceled"]) > .zx-icon {
|
|
299
353
|
color: var(--zx-color-bg-raised);
|
|
300
354
|
}
|
|
301
|
-
.zx-
|
|
355
|
+
.zx-status-icon[data-indicator="duplicate"]::after {
|
|
302
356
|
content: "";
|
|
303
357
|
inline-size: 8px;
|
|
304
358
|
block-size: 2px;
|
|
@@ -343,7 +397,7 @@
|
|
|
343
397
|
|
|
344
398
|
@media (prefers-reduced-motion: no-preference) {
|
|
345
399
|
.zx-select__loading {
|
|
346
|
-
animation: zx-select-spin
|
|
400
|
+
animation: zx-select-spin 720ms linear infinite;
|
|
347
401
|
}
|
|
348
402
|
}
|
|
349
403
|
|
|
@@ -352,3 +406,42 @@
|
|
|
352
406
|
transform: rotate(1turn);
|
|
353
407
|
}
|
|
354
408
|
}
|
|
409
|
+
|
|
410
|
+
/*
|
|
411
|
+
* Quiet fields. Inside `[data-zx-fields="quiet"]` — a property panel, an inspector — the control
|
|
412
|
+
* reads as its value: no border, no fill, no chevron or clear button. Hover brings the hover fill
|
|
413
|
+
* and the chevron back; focus or an open list brings back the border, the control fill and the
|
|
414
|
+
* focus ring. A disabled control never lights up.
|
|
415
|
+
*/
|
|
416
|
+
[data-zx-fields="quiet"] .zx-select__control,
|
|
417
|
+
[data-zx-fields="quiet"] .zx-select[aria-disabled="true"] .zx-select__control {
|
|
418
|
+
border-color: transparent;
|
|
419
|
+
background: transparent;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
[data-zx-fields="quiet"] .zx-select :is(.zx-select__toggle, .zx-select__clear) {
|
|
423
|
+
opacity: 0;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
[data-zx-fields="quiet"] .zx-select:not([aria-disabled="true"]):hover .zx-select__control {
|
|
427
|
+
background: var(--zx-color-bg-hover);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
[data-zx-fields="quiet"] .zx-select:not([aria-disabled="true"]):is(:hover, :focus-within, [data-state="open"]) :is(.zx-select__toggle, .zx-select__clear) {
|
|
431
|
+
opacity: 1;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
[data-zx-fields="quiet"] .zx-select:not([aria-disabled="true"]):is(:focus-within, [data-state="open"]) .zx-select__control {
|
|
435
|
+
border-color: var(--zx-color-border-control);
|
|
436
|
+
background: var(--zx-color-bg-control);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
440
|
+
[data-zx-fields="quiet"] .zx-select__control {
|
|
441
|
+
transition: background-color var(--zx-dur-fast) var(--zx-ease), border-color var(--zx-dur-fast) var(--zx-ease);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
[data-zx-fields="quiet"] .zx-select :is(.zx-select__toggle, .zx-select__clear) {
|
|
445
|
+
transition: opacity var(--zx-dur-fast) var(--zx-ease);
|
|
446
|
+
}
|
|
447
|
+
}
|