@zeyos/zx 2.2.1 → 2.3.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 +110 -0
- package/README.md +28 -2
- package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +67 -8
- package/dist/types/components/permission/permission.d.ts +3 -0
- package/dist/types/components/select/select.d.ts +36 -1
- package/dist/types/components/tabbox/tabbox.d.ts +12 -3
- package/dist/zx-compat.esm.js +302 -34
- package/dist/zx-compat.esm.min.js +1 -1
- package/dist/zx-compat.global.js +302 -34
- package/dist/zx-compat.global.min.js +3 -3
- package/dist/zx-zeyos.esm.js +280 -27
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +159 -33
- package/dist/zx.esm.js +302 -34
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +302 -34
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +420 -17
- package/docs/llms.md +54 -12
- package/package.json +1 -1
- package/src/components/date-picker/date-range-picker.css +7 -0
- package/src/components/fieldset/fieldset.css +7 -0
- package/src/components/form/form.css +7 -0
- package/src/components/multi-value-editor/multi-value-editor.css +99 -15
- package/src/components/multi-value-editor/multi-value-editor.js +235 -18
- package/src/components/navigation-bar/navigation-bar.css +7 -0
- package/src/components/permission/permission.js +3 -0
- package/src/components/search/search.css +10 -2
- package/src/components/select/select.css +6 -0
- package/src/components/select/select.js +99 -11
- package/src/components/stepper/stepper.css +12 -2
- package/src/components/tabbox/tabbox.css +13 -3
- package/src/components/tabbox/tabbox.js +34 -10
- package/styles/tokens/dark.css +13 -10
- package/styles/tokens/global.css +12 -0
- package/styles/tokens/semantic.css +9 -5
- package/styles/tokens/themes.css +72 -0
- package/styles/zx.css +1 -0
|
@@ -249,9 +249,19 @@
|
|
|
249
249
|
text-align: center;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
.zx-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
/* Chrome comes from the shared .zx-icon-btn ghost utility; only the box is reset here, because
|
|
253
|
+
a full control-height square would widen every closable tab. The extra .zx-tabbox raises the
|
|
254
|
+
specificity to match `.zx-scope .zx-icon-btn` in base.css, which sets the size. */
|
|
255
|
+
.zx-tabbox .zx-tabbox__close {
|
|
256
|
+
inline-size: 1.5rem;
|
|
257
|
+
block-size: 1.5rem;
|
|
258
|
+
margin-inline: calc(-1 * var(--zx-space-1));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* The tab under the pointer is already filled with bg-hover, so the close control needs a tint
|
|
262
|
+
that still reads on top of it — in both themes, over any variant's tab background. */
|
|
263
|
+
.zx-tabbox .zx-tabbox__close:hover {
|
|
264
|
+
background: color-mix(in srgb, var(--zx-color-text) 12%, transparent);
|
|
255
265
|
}
|
|
256
266
|
|
|
257
267
|
/* ----------------------------------------------------------------------- panels -- */
|
|
@@ -11,7 +11,7 @@ import { uid } from '../../core/util.js';
|
|
|
11
11
|
* @property {string} title Visible tab label.
|
|
12
12
|
* @property {TabContent} content Panel content or a lazy content factory.
|
|
13
13
|
* @property {string} [icon] Icon name passed to `icon()`, shown before the title.
|
|
14
|
-
* @property {boolean} [closable=false] Whether
|
|
14
|
+
* @property {boolean} [closable=false] Whether the tab shows a close control and Delete closes it.
|
|
15
15
|
* @property {boolean} [disabled=false] Whether the tab is unavailable.
|
|
16
16
|
*/
|
|
17
17
|
|
|
@@ -38,7 +38,8 @@ const VARIANTS = new Set(['divided', 'bracket', 'line', 'segmented']);
|
|
|
38
38
|
* control, for a toolbar or card header.
|
|
39
39
|
* @property {boolean} [keepAlive=true] Keep inactive panel elements mounted.
|
|
40
40
|
* @property {(event: CustomEvent<{name: string, previous: string|null}>) => void} [onchange] Change callback.
|
|
41
|
-
* @property {(event: CustomEvent<{name: string}>) => void} [onclose] Close callback
|
|
41
|
+
* @property {(event: CustomEvent<{name: string}>) => void} [onclose] Close callback, fired when the
|
|
42
|
+
* user dismisses a closable tab.
|
|
42
43
|
*/
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -121,6 +122,10 @@ export class Tabbox extends Component {
|
|
|
121
122
|
if (!tab || !tablist.contains(tab)) return;
|
|
122
123
|
const record = this._recordForTab(tab);
|
|
123
124
|
if (!record || record.definition.disabled) return;
|
|
125
|
+
if (event.target.closest?.('.zx-tabbox__close')) {
|
|
126
|
+
this._closeTab(record);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
124
129
|
this._setFocused(record);
|
|
125
130
|
this.openTab(record.definition.name);
|
|
126
131
|
});
|
|
@@ -168,9 +173,13 @@ export class Tabbox extends Component {
|
|
|
168
173
|
}
|
|
169
174
|
children.push(title, badge);
|
|
170
175
|
if (normalized.closable) {
|
|
176
|
+
// Deliberately a span and not a nested <button>: the tab itself is a button, and buttons
|
|
177
|
+
// cannot nest. The tablist click handler routes clicks that land in here to _closeTab(),
|
|
178
|
+
// and it stays out of the accessibility tree because Delete is the keyboard equivalent.
|
|
171
179
|
children.push(h('span', {
|
|
172
|
-
class: 'zx-tabbox__close',
|
|
173
|
-
ariaHidden: 'true'
|
|
180
|
+
class: 'zx-tabbox__close zx-icon-btn',
|
|
181
|
+
ariaHidden: 'true',
|
|
182
|
+
title: 'Close'
|
|
174
183
|
}, icon('x', { size: 14 })));
|
|
175
184
|
}
|
|
176
185
|
const tab = /** @type {HTMLButtonElement} */ (h('button', {
|
|
@@ -353,14 +362,28 @@ export class Tabbox extends Component {
|
|
|
353
362
|
}
|
|
354
363
|
if (event.key === 'Delete' && current.definition.closable) {
|
|
355
364
|
event.preventDefault();
|
|
356
|
-
|
|
357
|
-
if (!this._removeTab(current.definition.name, true)) return;
|
|
358
|
-
const remaining = this._tabs[Math.min(index, this._tabs.length - 1)] ?? this._tabs[index - 1];
|
|
359
|
-
const focusTarget = remaining && !remaining.definition.disabled ? remaining : this._active;
|
|
360
|
-
if (focusTarget) this._setFocused(focusTarget);
|
|
365
|
+
this._closeTab(current);
|
|
361
366
|
}
|
|
362
367
|
}
|
|
363
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Closes a tab on a user gesture, keeping roving focus inside the tablist.
|
|
371
|
+
* @param {TabRecord} record Tab to close.
|
|
372
|
+
* @returns {void}
|
|
373
|
+
* @fires Tabbox#close
|
|
374
|
+
*/
|
|
375
|
+
_closeTab(record) {
|
|
376
|
+
const index = this._tabs.indexOf(record);
|
|
377
|
+
// Clicking the close control focuses its tab first in most browsers, so the element about to
|
|
378
|
+
// be removed holds the focus; left alone, focus would fall back to <body>.
|
|
379
|
+
const held = record.tab.contains(document.activeElement);
|
|
380
|
+
if (!this._removeTab(record.definition.name, true)) return;
|
|
381
|
+
const remaining = this._tabs[Math.min(index, this._tabs.length - 1)] ?? this._tabs[index - 1];
|
|
382
|
+
const focusTarget = remaining && !remaining.definition.disabled ? remaining : this._active;
|
|
383
|
+
// Roving tabindex has to move even for a mouse close, or Tab has no entry point left.
|
|
384
|
+
if (focusTarget) this._setFocused(focusTarget, held);
|
|
385
|
+
}
|
|
386
|
+
|
|
364
387
|
/** @param {string} name @param {boolean} emitClose @returns {boolean} */
|
|
365
388
|
_removeTab(name, emitClose) {
|
|
366
389
|
const record = this._find(name);
|
|
@@ -453,7 +476,8 @@ export class Tabbox extends Component {
|
|
|
453
476
|
*/
|
|
454
477
|
|
|
455
478
|
/**
|
|
456
|
-
* Fired after a closable tab
|
|
479
|
+
* Fired after the user removes a closable tab, through its close control or Delete.
|
|
480
|
+
* `removeTab()` is silent.
|
|
457
481
|
* @event Tabbox#close
|
|
458
482
|
* @type {CustomEvent<{name: string}>}
|
|
459
483
|
*/
|
package/styles/tokens/dark.css
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* Zinc-950 page, Zinc-900 cards and popovers, Zinc-800 muted fills, translucent white borders
|
|
4
4
|
* (10%) and inputs (15%), Zinc-400 muted text.
|
|
5
5
|
*
|
|
6
|
+
* The accent roles take the light end of the `--zx-accent-*` ramp (300/400/500) where the light
|
|
7
|
+
* theme takes the dark end, so a preset that repoints the ramp lands correctly in both.
|
|
8
|
+
*
|
|
6
9
|
* The `[data-zx-theme="auto"]` block below repeats these assignments under a
|
|
7
10
|
* `prefers-color-scheme` query; CSS has no way to share a declaration block across a media
|
|
8
11
|
* boundary, so the two lists must be kept in sync.
|
|
@@ -15,7 +18,7 @@
|
|
|
15
18
|
--zx-color-bg-control: color-mix(in srgb, var(--zx-gray-0) 5%, transparent);
|
|
16
19
|
--zx-color-bg-muted: var(--zx-gray-800);
|
|
17
20
|
--zx-color-bg-hover: color-mix(in srgb, var(--zx-gray-0) 8%, transparent);
|
|
18
|
-
--zx-color-bg-selected: color-mix(in srgb, var(--zx-
|
|
21
|
+
--zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-400) 18%, var(--zx-gray-900));
|
|
19
22
|
--zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 75%, transparent);
|
|
20
23
|
--zx-color-border: color-mix(in srgb, var(--zx-gray-0) 10%, transparent);
|
|
21
24
|
--zx-color-border-strong: color-mix(in srgb, var(--zx-gray-0) 28%, transparent);
|
|
@@ -24,10 +27,10 @@
|
|
|
24
27
|
--zx-color-text-muted: var(--zx-gray-400);
|
|
25
28
|
--zx-color-text-placeholder: var(--zx-gray-500);
|
|
26
29
|
--zx-color-text-invert: var(--zx-gray-950);
|
|
27
|
-
--zx-color-accent: var(--zx-
|
|
28
|
-
--zx-color-accent-hover: var(--zx-
|
|
29
|
-
--zx-color-accent-active: var(--zx-
|
|
30
|
-
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-
|
|
30
|
+
--zx-color-accent: var(--zx-accent-400);
|
|
31
|
+
--zx-color-accent-hover: var(--zx-accent-300);
|
|
32
|
+
--zx-color-accent-active: var(--zx-accent-500);
|
|
33
|
+
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-400) 16%, var(--zx-gray-900));
|
|
31
34
|
--zx-color-on-accent: var(--zx-gray-950);
|
|
32
35
|
--zx-color-danger: var(--zx-red-400);
|
|
33
36
|
--zx-color-danger-bg: color-mix(in srgb, var(--zx-red-400) 16%, var(--zx-gray-900));
|
|
@@ -53,7 +56,7 @@
|
|
|
53
56
|
--zx-color-bg-control: color-mix(in srgb, var(--zx-gray-0) 5%, transparent);
|
|
54
57
|
--zx-color-bg-muted: var(--zx-gray-800);
|
|
55
58
|
--zx-color-bg-hover: color-mix(in srgb, var(--zx-gray-0) 8%, transparent);
|
|
56
|
-
--zx-color-bg-selected: color-mix(in srgb, var(--zx-
|
|
59
|
+
--zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-400) 18%, var(--zx-gray-900));
|
|
57
60
|
--zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 75%, transparent);
|
|
58
61
|
--zx-color-border: color-mix(in srgb, var(--zx-gray-0) 10%, transparent);
|
|
59
62
|
--zx-color-border-strong: color-mix(in srgb, var(--zx-gray-0) 28%, transparent);
|
|
@@ -62,10 +65,10 @@
|
|
|
62
65
|
--zx-color-text-muted: var(--zx-gray-400);
|
|
63
66
|
--zx-color-text-placeholder: var(--zx-gray-500);
|
|
64
67
|
--zx-color-text-invert: var(--zx-gray-950);
|
|
65
|
-
--zx-color-accent: var(--zx-
|
|
66
|
-
--zx-color-accent-hover: var(--zx-
|
|
67
|
-
--zx-color-accent-active: var(--zx-
|
|
68
|
-
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-
|
|
68
|
+
--zx-color-accent: var(--zx-accent-400);
|
|
69
|
+
--zx-color-accent-hover: var(--zx-accent-300);
|
|
70
|
+
--zx-color-accent-active: var(--zx-accent-500);
|
|
71
|
+
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-400) 16%, var(--zx-gray-900));
|
|
69
72
|
--zx-color-on-accent: var(--zx-gray-950);
|
|
70
73
|
--zx-color-danger: var(--zx-red-400);
|
|
71
74
|
--zx-color-danger-bg: color-mix(in srgb, var(--zx-red-400) 16%, var(--zx-gray-900));
|
package/styles/tokens/global.css
CHANGED
|
@@ -31,6 +31,18 @@
|
|
|
31
31
|
--zx-green-600: #007a55;
|
|
32
32
|
--zx-green-700: #006045;
|
|
33
33
|
|
|
34
|
+
/*
|
|
35
|
+
* Accent ramp — the indirection the semantic tier reads. It defaults to the Emerald ramp
|
|
36
|
+
* above, which is what makes a theme preset five declarations rather than a second copy of
|
|
37
|
+
* every semantic mapping: `tokens/themes.css` repoints these, and light, dark, and auto all
|
|
38
|
+
* follow because each of them picks its own stop off the ramp.
|
|
39
|
+
*/
|
|
40
|
+
--zx-accent-300: var(--zx-green-300);
|
|
41
|
+
--zx-accent-400: var(--zx-green-400);
|
|
42
|
+
--zx-accent-500: var(--zx-green-500);
|
|
43
|
+
--zx-accent-600: var(--zx-green-600);
|
|
44
|
+
--zx-accent-700: var(--zx-green-700);
|
|
45
|
+
|
|
34
46
|
/* Status */
|
|
35
47
|
--zx-red-400: #ff6467;
|
|
36
48
|
--zx-red-500: #e7000b;
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* The mapping follows the shadcn/ui preset `b2BVl11e4`: white surfaces, Zinc-100 hover/muted
|
|
5
5
|
* fills, Zinc-200 borders and inputs, Zinc-500 muted text, Zinc-950 body text, and the Nova
|
|
6
6
|
* control geometry (32px controls, `--radius` corners, a 3px translucent focus ring).
|
|
7
|
+
*
|
|
8
|
+
* The accent roles read `--zx-accent-*` rather than the green ramp directly, which is what lets
|
|
9
|
+
* `tokens/themes.css` retheme them. Status colours keep their own ramps on purpose — see the note
|
|
10
|
+
* in that file.
|
|
7
11
|
*/
|
|
8
12
|
:root,
|
|
9
13
|
[data-zx-theme="light"] {
|
|
@@ -14,7 +18,7 @@
|
|
|
14
18
|
--zx-color-bg-control: var(--zx-gray-0);
|
|
15
19
|
--zx-color-bg-muted: var(--zx-gray-100);
|
|
16
20
|
--zx-color-bg-hover: var(--zx-gray-100);
|
|
17
|
-
--zx-color-bg-selected: color-mix(in srgb, var(--zx-
|
|
21
|
+
--zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-600) 10%, var(--zx-gray-0));
|
|
18
22
|
--zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 50%, transparent);
|
|
19
23
|
--zx-color-border: var(--zx-gray-200);
|
|
20
24
|
--zx-color-border-strong: var(--zx-gray-300);
|
|
@@ -23,10 +27,10 @@
|
|
|
23
27
|
--zx-color-text-muted: var(--zx-gray-500);
|
|
24
28
|
--zx-color-text-placeholder: var(--zx-gray-400);
|
|
25
29
|
--zx-color-text-invert: var(--zx-gray-50);
|
|
26
|
-
--zx-color-accent: var(--zx-
|
|
27
|
-
--zx-color-accent-hover: var(--zx-
|
|
28
|
-
--zx-color-accent-active: var(--zx-
|
|
29
|
-
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-
|
|
30
|
+
--zx-color-accent: var(--zx-accent-600);
|
|
31
|
+
--zx-color-accent-hover: var(--zx-accent-700);
|
|
32
|
+
--zx-color-accent-active: var(--zx-accent-700);
|
|
33
|
+
--zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-600) 10%, var(--zx-gray-0));
|
|
30
34
|
--zx-color-on-accent: var(--zx-gray-0);
|
|
31
35
|
--zx-color-danger: var(--zx-red-500);
|
|
32
36
|
--zx-color-danger-bg: color-mix(in srgb, var(--zx-red-500) 10%, var(--zx-gray-0));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Standard theme presets.
|
|
3
|
+
*
|
|
4
|
+
* A preset repoints the tier-1 accent ramp — nothing else. The semantic tier picks its own stop
|
|
5
|
+
* off that ramp per polarity (600/700 on light surfaces, 300/400/500 on dark ones), so five
|
|
6
|
+
* declarations retheme light, dark, and auto at once, and every component follows without a
|
|
7
|
+
* second mapping to keep in sync.
|
|
8
|
+
*
|
|
9
|
+
* Set the preset alongside the theme: `<html data-zx-theme="dark" data-zx-preset="ocean">`.
|
|
10
|
+
* `zx` is the default and never needs stating; the attribute exists so an application can pin it.
|
|
11
|
+
*
|
|
12
|
+
* Status colours are deliberately not part of a preset. Danger, warning, and success mean the
|
|
13
|
+
* same thing whatever a product's brand colour is, and a preset that repainted them would leave
|
|
14
|
+
* an application with no reliable way to say "this failed".
|
|
15
|
+
*
|
|
16
|
+
* Every 600 clears 4.5:1 against white and against the light page, and every 400 clears it
|
|
17
|
+
* against the dark page, which is what keeps `--zx-color-on-accent` correct in both polarities.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/* Zx — the ZeyOS brand green on the shadcn Emerald ramp. The default. */
|
|
21
|
+
[data-zx-preset="zx"] {
|
|
22
|
+
--zx-accent-300: #5ee9b5;
|
|
23
|
+
--zx-accent-400: #21cc75;
|
|
24
|
+
--zx-accent-500: #009966;
|
|
25
|
+
--zx-accent-600: #007a55;
|
|
26
|
+
--zx-accent-700: #006045;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ZeyOS — the gold of the ZeyOS product marque, anchored at 400. */
|
|
30
|
+
[data-zx-preset="zeyos"] {
|
|
31
|
+
--zx-accent-300: #ffd9a8;
|
|
32
|
+
--zx-accent-400: #f7bc60;
|
|
33
|
+
--zx-accent-500: #d0952f;
|
|
34
|
+
--zx-accent-600: #96690f;
|
|
35
|
+
--zx-accent-700: #6f4e0b;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Ocean — the palette's own blue ramp, for products that read as utilities rather than brands. */
|
|
39
|
+
[data-zx-preset="ocean"] {
|
|
40
|
+
--zx-accent-300: #8ec5ff;
|
|
41
|
+
--zx-accent-400: #51a2ff;
|
|
42
|
+
--zx-accent-500: #2b7fff;
|
|
43
|
+
--zx-accent-600: #155dfc;
|
|
44
|
+
--zx-accent-700: #1447e6;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Violet */
|
|
48
|
+
[data-zx-preset="violet"] {
|
|
49
|
+
--zx-accent-300: #c4b4ff;
|
|
50
|
+
--zx-accent-400: #a684ff;
|
|
51
|
+
--zx-accent-500: #8e51ff;
|
|
52
|
+
--zx-accent-600: #7f22fe;
|
|
53
|
+
--zx-accent-700: #7008e7;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Rose */
|
|
57
|
+
[data-zx-preset="rose"] {
|
|
58
|
+
--zx-accent-300: #ffa1ad;
|
|
59
|
+
--zx-accent-400: #ff637e;
|
|
60
|
+
--zx-accent-500: #ff2056;
|
|
61
|
+
--zx-accent-600: #dc0039;
|
|
62
|
+
--zx-accent-700: #a80030;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Slate — a near-neutral accent, for screens where the data should carry the colour. */
|
|
66
|
+
[data-zx-preset="slate"] {
|
|
67
|
+
--zx-accent-300: #cad5e2;
|
|
68
|
+
--zx-accent-400: #90a1b9;
|
|
69
|
+
--zx-accent-500: #62748e;
|
|
70
|
+
--zx-accent-600: #45556c;
|
|
71
|
+
--zx-accent-700: #314158;
|
|
72
|
+
}
|