@xenosystem/elements-react 0.0.3 → 0.0.5
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/LICENSE +18 -18
- package/README.md +41 -41
- package/dist/containers/Chip.js +1 -1
- package/dist/containers/Panel.js +1 -1
- package/package.json +58 -58
- package/src/chrome-separated.css +132 -132
- package/src/chrome-unified.css +72 -72
- package/src/containers/Badges.css +116 -116
- package/src/containers/avatar.css +70 -70
- package/src/containers/card.css +75 -75
- package/src/containers/chip.css +103 -103
- package/src/containers/list-row.css +132 -132
- package/src/containers/message-bubble.css +112 -112
- package/src/containers/panel.css +125 -120
- package/src/containers/table.css +102 -102
- package/src/containers/tile.css +17 -17
- package/src/content/callout.css +77 -77
- package/src/content/caret.css +30 -30
- package/src/content/code-block.css +159 -159
- package/src/content/collapsible.css +80 -80
- package/src/content/inline-code.css +14 -14
- package/src/content/model-picker.css +219 -219
- package/src/content/source-card.css +99 -99
- package/src/content/sources-disclosure.css +118 -118
- package/src/controls.css +453 -453
- package/src/fonts.css +34 -34
- package/src/forms/Checkbox.css +114 -114
- package/src/forms/RadioGroup.css +115 -115
- package/src/goo.css +97 -97
- package/src/icon-motion.css +1909 -1909
- package/src/layout/ResizablePanel.css +79 -79
- package/src/nav/sidebar.css +296 -296
- package/src/overlays/date-time-picker.css +238 -238
- package/src/overlays/menu.css +195 -195
- package/src/overlays/modal.css +167 -167
- package/src/overlays/picker-field.css +81 -81
- package/src/overlays/pill-filter.css +129 -129
- package/src/overlays/reveal.css +56 -56
- package/src/overlays/segmented-control.css +185 -185
- package/src/overlays/tabs.css +143 -143
- package/src/overlays/tooltip.css +126 -126
- package/src/scrollbar.css +184 -184
- package/src/size.css +179 -179
- package/src/status/progress-bar.css +88 -88
- package/src/status/spinner.css +33 -33
- package/src/status/statusindicator.css +65 -65
- package/src/status/steptimeline.css +137 -137
- package/src/status/thinkingcube.css +75 -75
- package/src/xeno-element.css +60 -60
- package/src/xeno-elements.css +71 -71
- package/src/xeno-theme.css +112 -99
package/src/containers/card.css
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Card — the base surface box. Monochrome shell: background + hairline border + card radius; depth on the
|
|
3
|
-
* `elevated` variant is the darker `--xeno-elevated` token plus one soft (hue-free) shadow. The hover-lift
|
|
4
|
-
* is opt-in via `data-interactive` and its transform lives behind `prefers-reduced-motion` — the border
|
|
5
|
-
* brighten still applies when motion is reduced. Only theme tokens; no literal colours (shadow excepted).
|
|
6
|
-
*/
|
|
7
|
-
.xeno-card {
|
|
8
|
-
display: flex;
|
|
9
|
-
flex-direction: column;
|
|
10
|
-
padding: var(--xeno-chrome-card-pad);
|
|
11
|
-
background: var(--xeno-chrome-card-bg);
|
|
12
|
-
border: var(--xeno-chrome-card-border);
|
|
13
|
-
border-radius: var(--xeno-chrome-card-radius);
|
|
14
|
-
color: var(--xeno-text);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.xeno-card[data-variant='elevated'] {
|
|
18
|
-
background: var(--xeno-chrome-card-elevated-bg);
|
|
19
|
-
box-shadow: var(--xeno-chrome-card-shadow);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* Body — the default slot. min-width:0 keeps flex-row children from overflowing the card. */
|
|
23
|
-
.xeno-card-body {
|
|
24
|
-
min-width: 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/* Header — a titled slot split from the body by an inset hairline. */
|
|
28
|
-
.xeno-card-header {
|
|
29
|
-
margin-bottom: 11px;
|
|
30
|
-
padding-bottom: 11px;
|
|
31
|
-
border-bottom: var(--xeno-chrome-divider);
|
|
32
|
-
color: var(--xeno-text);
|
|
33
|
-
font-size: 14px;
|
|
34
|
-
font-weight: 600;
|
|
35
|
-
line-height: 1.2;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/* Footer — a trailing slot, mirror of the header, quieter text. */
|
|
39
|
-
.xeno-card-footer {
|
|
40
|
-
margin-top: 11px;
|
|
41
|
-
padding-top: 11px;
|
|
42
|
-
border-top: var(--xeno-chrome-divider);
|
|
43
|
-
color: var(--xeno-muted);
|
|
44
|
-
font-size: 13px;
|
|
45
|
-
line-height: 1.3;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* Interactive — the sole hover-lift XENO allows. Border brighten is safe without motion. */
|
|
49
|
-
.xeno-card[data-interactive='true'] {
|
|
50
|
-
cursor: pointer;
|
|
51
|
-
}
|
|
52
|
-
.xeno-card[data-interactive='true']:hover {
|
|
53
|
-
border-color: var(--xeno-muted);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/* Strong lift — the artifact-card affordance: a bigger rise + one soft, hue-free shadow. The shadow is
|
|
57
|
-
safe without motion, so it sits outside the reduced-motion guard; only the transform is gated. */
|
|
58
|
-
.xeno-card[data-interactive='true'][data-lift='strong']:hover {
|
|
59
|
-
box-shadow: var(--xeno-chrome-card-lift);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
63
|
-
.xeno-card[data-interactive='true'] {
|
|
64
|
-
transition:
|
|
65
|
-
transform var(--xeno-dur) var(--xeno-ease),
|
|
66
|
-
border-color var(--xeno-dur) ease,
|
|
67
|
-
box-shadow var(--xeno-dur) ease;
|
|
68
|
-
}
|
|
69
|
-
.xeno-card[data-interactive='true']:hover {
|
|
70
|
-
transform: translateY(-1px);
|
|
71
|
-
}
|
|
72
|
-
.xeno-card[data-interactive='true'][data-lift='strong']:hover {
|
|
73
|
-
transform: translateY(-3px);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Card — the base surface box. Monochrome shell: background + hairline border + card radius; depth on the
|
|
3
|
+
* `elevated` variant is the darker `--xeno-elevated` token plus one soft (hue-free) shadow. The hover-lift
|
|
4
|
+
* is opt-in via `data-interactive` and its transform lives behind `prefers-reduced-motion` — the border
|
|
5
|
+
* brighten still applies when motion is reduced. Only theme tokens; no literal colours (shadow excepted).
|
|
6
|
+
*/
|
|
7
|
+
.xeno-card {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
padding: var(--xeno-chrome-card-pad);
|
|
11
|
+
background: var(--xeno-chrome-card-bg);
|
|
12
|
+
border: var(--xeno-chrome-card-border);
|
|
13
|
+
border-radius: var(--xeno-chrome-card-radius);
|
|
14
|
+
color: var(--xeno-text);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.xeno-card[data-variant='elevated'] {
|
|
18
|
+
background: var(--xeno-chrome-card-elevated-bg);
|
|
19
|
+
box-shadow: var(--xeno-chrome-card-shadow);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Body — the default slot. min-width:0 keeps flex-row children from overflowing the card. */
|
|
23
|
+
.xeno-card-body {
|
|
24
|
+
min-width: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Header — a titled slot split from the body by an inset hairline. */
|
|
28
|
+
.xeno-card-header {
|
|
29
|
+
margin-bottom: 11px;
|
|
30
|
+
padding-bottom: 11px;
|
|
31
|
+
border-bottom: var(--xeno-chrome-divider);
|
|
32
|
+
color: var(--xeno-text);
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
line-height: 1.2;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Footer — a trailing slot, mirror of the header, quieter text. */
|
|
39
|
+
.xeno-card-footer {
|
|
40
|
+
margin-top: 11px;
|
|
41
|
+
padding-top: 11px;
|
|
42
|
+
border-top: var(--xeno-chrome-divider);
|
|
43
|
+
color: var(--xeno-muted-text);
|
|
44
|
+
font-size: 13px;
|
|
45
|
+
line-height: 1.3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Interactive — the sole hover-lift XENO allows. Border brighten is safe without motion. */
|
|
49
|
+
.xeno-card[data-interactive='true'] {
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
}
|
|
52
|
+
.xeno-card[data-interactive='true']:hover {
|
|
53
|
+
border-color: var(--xeno-muted);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Strong lift — the artifact-card affordance: a bigger rise + one soft, hue-free shadow. The shadow is
|
|
57
|
+
safe without motion, so it sits outside the reduced-motion guard; only the transform is gated. */
|
|
58
|
+
.xeno-card[data-interactive='true'][data-lift='strong']:hover {
|
|
59
|
+
box-shadow: var(--xeno-chrome-card-lift);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
63
|
+
.xeno-card[data-interactive='true'] {
|
|
64
|
+
transition:
|
|
65
|
+
transform var(--xeno-dur) var(--xeno-ease),
|
|
66
|
+
border-color var(--xeno-dur) ease,
|
|
67
|
+
box-shadow var(--xeno-dur) ease;
|
|
68
|
+
}
|
|
69
|
+
.xeno-card[data-interactive='true']:hover {
|
|
70
|
+
transform: translateY(-1px);
|
|
71
|
+
}
|
|
72
|
+
.xeno-card[data-interactive='true'][data-lift='strong']:hover {
|
|
73
|
+
transform: translateY(-3px);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/containers/chip.css
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Chip — a small selectable/removable token. SQUARE (radius-control), 1px hairline border, monochrome
|
|
3
|
-
* shell. State is driven by `data-*` on the root; size metrics arrive as inline `--xeno-h/-padx/-gap/
|
|
4
|
-
* -font` vars set from the size tokens, so a size can never drift from the data. No literal colours.
|
|
5
|
-
*/
|
|
6
|
-
.xeno-chip {
|
|
7
|
-
display: inline-flex;
|
|
8
|
-
align-items: center;
|
|
9
|
-
height: var(--xeno-h, 32px);
|
|
10
|
-
max-width: 100%;
|
|
11
|
-
color: var(--xeno-text);
|
|
12
|
-
background: transparent;
|
|
13
|
-
border: 1px solid var(--xeno-border);
|
|
14
|
-
border-radius: var(--xeno-radius-control);
|
|
15
|
-
font-family: inherit;
|
|
16
|
-
font-size: var(--xeno-font, 14px);
|
|
17
|
-
font-weight: 500;
|
|
18
|
-
line-height: 1;
|
|
19
|
-
white-space: nowrap;
|
|
20
|
-
user-select: none;
|
|
21
|
-
overflow: hidden; /* clips inner hover fills to the rounded corners */
|
|
22
|
-
}
|
|
23
|
-
.xeno-chip[data-selection='on'] {
|
|
24
|
-
background: var(--xeno-control);
|
|
25
|
-
}
|
|
26
|
-
.xeno-chip[data-availability='disabled'] {
|
|
27
|
-
opacity: 0.4;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/* Body — the label region: a plain span, or a toggle <button> when selectable. */
|
|
31
|
-
.xeno-chip-body {
|
|
32
|
-
display: inline-flex;
|
|
33
|
-
align-items: center;
|
|
34
|
-
gap: var(--xeno-gap, 6px);
|
|
35
|
-
height: 100%;
|
|
36
|
-
min-width: 0;
|
|
37
|
-
padding: 0 var(--xeno-padx, 12px);
|
|
38
|
-
color: inherit;
|
|
39
|
-
background: transparent;
|
|
40
|
-
border: none;
|
|
41
|
-
font: inherit;
|
|
42
|
-
line-height: 1;
|
|
43
|
-
}
|
|
44
|
-
.xeno-chip[data-removable='true'] .xeno-chip-body {
|
|
45
|
-
padding-right: var(--xeno-gap, 6px);
|
|
46
|
-
}
|
|
47
|
-
.xeno-chip-label {
|
|
48
|
-
overflow: hidden;
|
|
49
|
-
text-overflow: ellipsis;
|
|
50
|
-
white-space: nowrap;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/* Selectable body toggles the selection axis (aria-pressed); hover/press are CSS, not attributes. */
|
|
54
|
-
.xeno-chip-select {
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
transition:
|
|
57
|
-
background var(--xeno-dur) ease,
|
|
58
|
-
color var(--xeno-dur) ease;
|
|
59
|
-
}
|
|
60
|
-
.xeno-chip-select:hover:not(:disabled) {
|
|
61
|
-
background: var(--xeno-hover);
|
|
62
|
-
}
|
|
63
|
-
.xeno-chip-select:focus-visible {
|
|
64
|
-
outline: none;
|
|
65
|
-
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
66
|
-
}
|
|
67
|
-
.xeno-chip-select:disabled {
|
|
68
|
-
cursor: not-allowed;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/* Remove — a bare 'x' button; muted ink that resolves to text on hover. */
|
|
72
|
-
.xeno-chip-remove {
|
|
73
|
-
display: inline-flex;
|
|
74
|
-
align-items: center;
|
|
75
|
-
justify-content: center;
|
|
76
|
-
height: 100%;
|
|
77
|
-
padding: 0 6px;
|
|
78
|
-
color: var(--xeno-muted);
|
|
79
|
-
background: transparent;
|
|
80
|
-
border: none;
|
|
81
|
-
cursor: pointer;
|
|
82
|
-
transition:
|
|
83
|
-
background var(--xeno-dur) ease,
|
|
84
|
-
color var(--xeno-dur) ease;
|
|
85
|
-
}
|
|
86
|
-
.xeno-chip-remove:hover:not(:disabled) {
|
|
87
|
-
color: var(--xeno-text);
|
|
88
|
-
background: var(--xeno-hover);
|
|
89
|
-
}
|
|
90
|
-
.xeno-chip-remove:focus-visible {
|
|
91
|
-
outline: none;
|
|
92
|
-
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
93
|
-
}
|
|
94
|
-
.xeno-chip-remove:disabled {
|
|
95
|
-
cursor: not-allowed;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@media (prefers-reduced-motion: reduce) {
|
|
99
|
-
.xeno-chip-select,
|
|
100
|
-
.xeno-chip-remove {
|
|
101
|
-
transition: none;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Chip — a small selectable/removable token. SQUARE (radius-control), 1px hairline border, monochrome
|
|
3
|
+
* shell. State is driven by `data-*` on the root; size metrics arrive as inline `--xeno-h/-padx/-gap/
|
|
4
|
+
* -font` vars set from the size tokens, so a size can never drift from the data. No literal colours.
|
|
5
|
+
*/
|
|
6
|
+
.xeno-chip {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
height: var(--xeno-h, 32px);
|
|
10
|
+
max-width: 100%;
|
|
11
|
+
color: var(--xeno-text);
|
|
12
|
+
background: transparent;
|
|
13
|
+
border: 1px solid var(--xeno-border);
|
|
14
|
+
border-radius: var(--xeno-radius-control);
|
|
15
|
+
font-family: inherit;
|
|
16
|
+
font-size: var(--xeno-font, 14px);
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
line-height: 1;
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
user-select: none;
|
|
21
|
+
overflow: hidden; /* clips inner hover fills to the rounded corners */
|
|
22
|
+
}
|
|
23
|
+
.xeno-chip[data-selection='on'] {
|
|
24
|
+
background: var(--xeno-control);
|
|
25
|
+
}
|
|
26
|
+
.xeno-chip[data-availability='disabled'] {
|
|
27
|
+
opacity: 0.4;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Body — the label region: a plain span, or a toggle <button> when selectable. */
|
|
31
|
+
.xeno-chip-body {
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: var(--xeno-gap, 6px);
|
|
35
|
+
height: 100%;
|
|
36
|
+
min-width: 0;
|
|
37
|
+
padding: 0 var(--xeno-padx, 12px);
|
|
38
|
+
color: inherit;
|
|
39
|
+
background: transparent;
|
|
40
|
+
border: none;
|
|
41
|
+
font: inherit;
|
|
42
|
+
line-height: 1;
|
|
43
|
+
}
|
|
44
|
+
.xeno-chip[data-removable='true'] .xeno-chip-body {
|
|
45
|
+
padding-right: var(--xeno-gap, 6px);
|
|
46
|
+
}
|
|
47
|
+
.xeno-chip-label {
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
text-overflow: ellipsis;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Selectable body toggles the selection axis (aria-pressed); hover/press are CSS, not attributes. */
|
|
54
|
+
.xeno-chip-select {
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
transition:
|
|
57
|
+
background var(--xeno-dur) ease,
|
|
58
|
+
color var(--xeno-dur) ease;
|
|
59
|
+
}
|
|
60
|
+
.xeno-chip-select:hover:not(:disabled) {
|
|
61
|
+
background: var(--xeno-hover);
|
|
62
|
+
}
|
|
63
|
+
.xeno-chip-select:focus-visible {
|
|
64
|
+
outline: none;
|
|
65
|
+
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
66
|
+
}
|
|
67
|
+
.xeno-chip-select:disabled {
|
|
68
|
+
cursor: not-allowed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Remove — a bare 'x' button; muted ink that resolves to text on hover. */
|
|
72
|
+
.xeno-chip-remove {
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
height: 100%;
|
|
77
|
+
padding: 0 6px;
|
|
78
|
+
color: var(--xeno-muted);
|
|
79
|
+
background: transparent;
|
|
80
|
+
border: none;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
transition:
|
|
83
|
+
background var(--xeno-dur) ease,
|
|
84
|
+
color var(--xeno-dur) ease;
|
|
85
|
+
}
|
|
86
|
+
.xeno-chip-remove:hover:not(:disabled) {
|
|
87
|
+
color: var(--xeno-text);
|
|
88
|
+
background: var(--xeno-hover);
|
|
89
|
+
}
|
|
90
|
+
.xeno-chip-remove:focus-visible {
|
|
91
|
+
outline: none;
|
|
92
|
+
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
93
|
+
}
|
|
94
|
+
.xeno-chip-remove:disabled {
|
|
95
|
+
cursor: not-allowed;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@media (prefers-reduced-motion: reduce) {
|
|
99
|
+
.xeno-chip-select,
|
|
100
|
+
.xeno-chip-remove {
|
|
101
|
+
transition: none;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ListRow — a selectable / actionable list row. CSS-first: the `selection` and `availability` axes
|
|
3
|
-
* arrive as `data-*` attributes on the root; interaction (hover / press / focus) is pure CSS. Depth is
|
|
4
|
-
* hairline borders only — monochrome shell, no coloured glow. Only the theme tokens from
|
|
5
|
-
* `xeno-theme.css` are used; no literal colours.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
.xeno-list-row {
|
|
9
|
-
display: flex;
|
|
10
|
-
align-items: center;
|
|
11
|
-
gap: 12px;
|
|
12
|
-
width: 100%;
|
|
13
|
-
box-sizing: border-box;
|
|
14
|
-
min-width: 0;
|
|
15
|
-
margin: 0;
|
|
16
|
-
padding: 8px 12px;
|
|
17
|
-
color: var(--xeno-text);
|
|
18
|
-
text-align: left;
|
|
19
|
-
background: transparent;
|
|
20
|
-
border: 1px solid transparent;
|
|
21
|
-
border-radius: var(--xeno-radius-md);
|
|
22
|
-
cursor: default;
|
|
23
|
-
transition:
|
|
24
|
-
background var(--xeno-dur) ease,
|
|
25
|
-
border-color var(--xeno-dur) ease;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* Reset the native <button> chrome so a button row reads exactly like a div row. */
|
|
29
|
-
button.xeno-list-row {
|
|
30
|
-
font: inherit;
|
|
31
|
-
appearance: none;
|
|
32
|
-
-webkit-appearance: none;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/* Interactive rows (a real button, or a div carrying role=button / role=option) invite the pointer. */
|
|
36
|
-
button.xeno-list-row:not(:disabled),
|
|
37
|
-
.xeno-list-row[role='button'],
|
|
38
|
-
.xeno-list-row[role='option'] {
|
|
39
|
-
cursor: pointer;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/* Hover — only interactive, enabled, unselected rows lift onto --xeno-hover. */
|
|
43
|
-
button.xeno-list-row:not(:disabled):hover,
|
|
44
|
-
.xeno-list-row[role='button']:not([aria-disabled='true']):hover,
|
|
45
|
-
.xeno-list-row[role='option']:not([aria-disabled='true']):hover {
|
|
46
|
-
background: var(--xeno-hover);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* Selection wins over hover — a selected row stays on the solid control fill. */
|
|
50
|
-
.xeno-list-row[data-selection='on'],
|
|
51
|
-
button.xeno-list-row[data-selection='on']:not(:disabled):hover,
|
|
52
|
-
.xeno-list-row[role='button'][data-selection='on']:hover,
|
|
53
|
-
.xeno-list-row[role='option'][data-selection='on']:hover {
|
|
54
|
-
background: var(--xeno-control);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.xeno-list-row:focus-visible {
|
|
58
|
-
outline: none;
|
|
59
|
-
box-shadow:
|
|
60
|
-
0 0 0 2px var(--xeno-canvas),
|
|
61
|
-
0 0 0 4px var(--xeno-border);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
button.xeno-list-row:active:not(:disabled) {
|
|
65
|
-
transform: scale(0.995);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.xeno-list-row:disabled,
|
|
69
|
-
.xeno-list-row[data-availability='disabled'] {
|
|
70
|
-
opacity: 0.4;
|
|
71
|
-
cursor: not-allowed;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* ── Slots ───────────────────────────────────────────────────────────────────────── */
|
|
75
|
-
|
|
76
|
-
/* Leading — glyph / avatar. Fixed, never shrinks. Its own children keep their intrinsic colour. */
|
|
77
|
-
.xeno-list-row-leading {
|
|
78
|
-
display: inline-flex;
|
|
79
|
-
align-items: center;
|
|
80
|
-
justify-content: center;
|
|
81
|
-
flex: none;
|
|
82
|
-
color: var(--xeno-muted);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/* Middle — the truncation column. min-width:0 lets the title/subtitle ellipsize inside the flex row. */
|
|
86
|
-
.xeno-list-row-body {
|
|
87
|
-
display: flex;
|
|
88
|
-
flex: 1 1 auto;
|
|
89
|
-
flex-direction: column;
|
|
90
|
-
gap: 2px;
|
|
91
|
-
min-width: 0;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.xeno-list-row-title {
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
font-size: 14px;
|
|
97
|
-
font-weight: 500;
|
|
98
|
-
line-height: 1.3;
|
|
99
|
-
color: var(--xeno-text);
|
|
100
|
-
white-space: nowrap;
|
|
101
|
-
text-overflow: ellipsis;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.xeno-list-row-subtitle {
|
|
105
|
-
overflow: hidden;
|
|
106
|
-
font-size: 12px;
|
|
107
|
-
font-weight: 400;
|
|
108
|
-
line-height: 1.3;
|
|
109
|
-
color: var(--xeno-muted);
|
|
110
|
-
white-space: nowrap;
|
|
111
|
-
text-overflow: ellipsis;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/* Trailing — meta / actions pinned to the end. Fixed, never shrinks. */
|
|
115
|
-
.xeno-list-row-trailing {
|
|
116
|
-
display: inline-flex;
|
|
117
|
-
align-items: center;
|
|
118
|
-
gap: 6px;
|
|
119
|
-
flex: none;
|
|
120
|
-
margin-left: auto;
|
|
121
|
-
font-size: 12px;
|
|
122
|
-
color: var(--xeno-muted);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
@media (prefers-reduced-motion: reduce) {
|
|
126
|
-
.xeno-list-row {
|
|
127
|
-
transition: none;
|
|
128
|
-
}
|
|
129
|
-
button.xeno-list-row:active:not(:disabled) {
|
|
130
|
-
transform: none;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* ListRow — a selectable / actionable list row. CSS-first: the `selection` and `availability` axes
|
|
3
|
+
* arrive as `data-*` attributes on the root; interaction (hover / press / focus) is pure CSS. Depth is
|
|
4
|
+
* hairline borders only — monochrome shell, no coloured glow. Only the theme tokens from
|
|
5
|
+
* `xeno-theme.css` are used; no literal colours.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
.xeno-list-row {
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: 12px;
|
|
12
|
+
width: 100%;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
min-width: 0;
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 8px 12px;
|
|
17
|
+
color: var(--xeno-text);
|
|
18
|
+
text-align: left;
|
|
19
|
+
background: transparent;
|
|
20
|
+
border: 1px solid transparent;
|
|
21
|
+
border-radius: var(--xeno-radius-md);
|
|
22
|
+
cursor: default;
|
|
23
|
+
transition:
|
|
24
|
+
background var(--xeno-dur) ease,
|
|
25
|
+
border-color var(--xeno-dur) ease;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Reset the native <button> chrome so a button row reads exactly like a div row. */
|
|
29
|
+
button.xeno-list-row {
|
|
30
|
+
font: inherit;
|
|
31
|
+
appearance: none;
|
|
32
|
+
-webkit-appearance: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Interactive rows (a real button, or a div carrying role=button / role=option) invite the pointer. */
|
|
36
|
+
button.xeno-list-row:not(:disabled),
|
|
37
|
+
.xeno-list-row[role='button'],
|
|
38
|
+
.xeno-list-row[role='option'] {
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Hover — only interactive, enabled, unselected rows lift onto --xeno-hover. */
|
|
43
|
+
button.xeno-list-row:not(:disabled):hover,
|
|
44
|
+
.xeno-list-row[role='button']:not([aria-disabled='true']):hover,
|
|
45
|
+
.xeno-list-row[role='option']:not([aria-disabled='true']):hover {
|
|
46
|
+
background: var(--xeno-hover);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Selection wins over hover — a selected row stays on the solid control fill. */
|
|
50
|
+
.xeno-list-row[data-selection='on'],
|
|
51
|
+
button.xeno-list-row[data-selection='on']:not(:disabled):hover,
|
|
52
|
+
.xeno-list-row[role='button'][data-selection='on']:hover,
|
|
53
|
+
.xeno-list-row[role='option'][data-selection='on']:hover {
|
|
54
|
+
background: var(--xeno-control);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.xeno-list-row:focus-visible {
|
|
58
|
+
outline: none;
|
|
59
|
+
box-shadow:
|
|
60
|
+
0 0 0 2px var(--xeno-canvas),
|
|
61
|
+
0 0 0 4px var(--xeno-border);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
button.xeno-list-row:active:not(:disabled) {
|
|
65
|
+
transform: scale(0.995);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.xeno-list-row:disabled,
|
|
69
|
+
.xeno-list-row[data-availability='disabled'] {
|
|
70
|
+
opacity: 0.4;
|
|
71
|
+
cursor: not-allowed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ── Slots ───────────────────────────────────────────────────────────────────────── */
|
|
75
|
+
|
|
76
|
+
/* Leading — glyph / avatar. Fixed, never shrinks. Its own children keep their intrinsic colour. */
|
|
77
|
+
.xeno-list-row-leading {
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
flex: none;
|
|
82
|
+
color: var(--xeno-muted);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Middle — the truncation column. min-width:0 lets the title/subtitle ellipsize inside the flex row. */
|
|
86
|
+
.xeno-list-row-body {
|
|
87
|
+
display: flex;
|
|
88
|
+
flex: 1 1 auto;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
gap: 2px;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.xeno-list-row-title {
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
font-size: 14px;
|
|
97
|
+
font-weight: 500;
|
|
98
|
+
line-height: 1.3;
|
|
99
|
+
color: var(--xeno-text);
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
text-overflow: ellipsis;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.xeno-list-row-subtitle {
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
font-size: 12px;
|
|
107
|
+
font-weight: 400;
|
|
108
|
+
line-height: 1.3;
|
|
109
|
+
color: var(--xeno-muted);
|
|
110
|
+
white-space: nowrap;
|
|
111
|
+
text-overflow: ellipsis;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Trailing — meta / actions pinned to the end. Fixed, never shrinks. */
|
|
115
|
+
.xeno-list-row-trailing {
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: 6px;
|
|
119
|
+
flex: none;
|
|
120
|
+
margin-left: auto;
|
|
121
|
+
font-size: 12px;
|
|
122
|
+
color: var(--xeno-muted);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (prefers-reduced-motion: reduce) {
|
|
126
|
+
.xeno-list-row {
|
|
127
|
+
transition: none;
|
|
128
|
+
}
|
|
129
|
+
button.xeno-list-row:active:not(:disabled) {
|
|
130
|
+
transform: none;
|
|
131
|
+
}
|
|
132
|
+
}
|