canny-ui 6.7.0 → 7.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/dist/canny-ui.min.css +1 -1
- package/dist/table-resize.js +16 -1
- package/package.json +1 -1
- package/src/_utilities.scss +4 -4
- package/src/base/_motion.scss +32 -0
- package/src/base/_reset.scss +7 -0
- package/src/base/_scrollbar-mixin.scss +84 -0
- package/src/base/_touch.scss +60 -0
- package/src/canny-ui.scss +5 -0
- package/src/components/_accordion.scss +10 -1
- package/src/components/_alerts.scss +18 -8
- package/src/components/_autocomplete.scss +16 -10
- package/src/components/_avatar.scss +22 -1
- package/src/components/_breadcrumb.scss +36 -2
- package/src/components/_buttons.scss +35 -24
- package/src/components/_charts-extra.scss +432 -0
- package/src/components/_charts.scss +90 -0
- package/src/components/_chip.scss +8 -7
- package/src/components/_command-palette.scss +27 -5
- package/src/components/_confirm.scss +14 -0
- package/src/components/_datatable.scss +383 -53
- package/src/components/_datepicker.scss +44 -21
- package/src/components/_dialog.scss +12 -0
- package/src/components/_drawer.scss +12 -0
- package/src/components/_fields.scss +115 -27
- package/src/components/_forms.scss +28 -10
- package/src/components/_gantt.scss +554 -0
- package/src/components/_inputs.scss +12 -7
- package/src/components/_list.scss +37 -3
- package/src/components/_menu.scss +23 -9
- package/src/components/_navbar.scss +98 -7
- package/src/components/_pagination.scss +105 -2
- package/src/components/_panels.scss +19 -5
- package/src/components/_popover.scss +3 -5
- package/src/components/_progress.scss +31 -0
- package/src/components/_scrollbar.scss +16 -159
- package/src/components/_sidebar.scss +24 -20
- package/src/components/_skeleton.scss +40 -1
- package/src/components/_slider.scss +8 -2
- package/src/components/_stepper.scss +22 -4
- package/src/components/_table.scss +23 -3
- package/src/components/_tabs.scss +120 -4
- package/src/components/_timeline.scss +26 -0
- package/src/components/_toast.scss +24 -12
- package/src/components/_tooltip-radix.scss +25 -4
- package/src/components/_tree.scss +51 -3
- package/src/components/_uploader.scss +97 -1
- package/src/scripts/table-resize.js +16 -1
- package/src/tokens/_semantic.scss +85 -21
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use '../base/scrollbar-mixin' as sb;
|
|
1
2
|
@use '../tokens/primitives' as *;
|
|
2
3
|
|
|
3
4
|
// ── Sidebar ───────────────────────────────────────────────────
|
|
@@ -78,7 +79,7 @@
|
|
|
78
79
|
&:active { transform: scale(0.96); }
|
|
79
80
|
|
|
80
81
|
&:focus-visible {
|
|
81
|
-
outline: 2px solid var(--
|
|
82
|
+
outline: 2px solid var(--border-focus);
|
|
82
83
|
outline-offset: 2px;
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -104,14 +105,19 @@
|
|
|
104
105
|
.cny-sidebar-nav {
|
|
105
106
|
display: flex;
|
|
106
107
|
flex-direction: column;
|
|
107
|
-
gap:
|
|
108
|
+
// No gap between rows: each row carries a 1px transparent border instead, so
|
|
109
|
+
// the hover target is contiguous (no dead strip between items).
|
|
110
|
+
gap: 0;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
.cny-sidebar-item {
|
|
111
114
|
display: flex;
|
|
112
115
|
align-items: center;
|
|
113
116
|
gap: $space-3;
|
|
114
|
-
padding:
|
|
117
|
+
padding: 7px $space-3;
|
|
118
|
+
border-top: 1px solid transparent;
|
|
119
|
+
border-bottom: 1px solid transparent;
|
|
120
|
+
background-clip: padding-box;
|
|
115
121
|
// Break out of the rail's left padding so the surface meets the sidebar edge
|
|
116
122
|
// with no gap, then hand the content back its indent so nothing shifts. The
|
|
117
123
|
// right side stays inset, and only the right corners are curved.
|
|
@@ -151,8 +157,8 @@
|
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
&:focus-visible {
|
|
154
|
-
outline: 2px solid var(--
|
|
155
|
-
outline-offset: -
|
|
160
|
+
outline: 2px solid var(--border-focus);
|
|
161
|
+
outline-offset: -2px;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
&.active {
|
|
@@ -164,7 +170,8 @@
|
|
|
164
170
|
// The resting badge is a light surface; on a solid fill it needs to read
|
|
165
171
|
// as part of the row rather than a chip sitting on top of it.
|
|
166
172
|
.cny-sidebar-item-badge {
|
|
167
|
-
|
|
173
|
+
// text-primary is the opposite pole of primary-on in both themes, so the overlay always lifts contrast
|
|
174
|
+
background: color-mix(in srgb, var(--text-primary) 22%, transparent);
|
|
168
175
|
color: var(--color-primary-on);
|
|
169
176
|
}
|
|
170
177
|
}
|
|
@@ -178,8 +185,10 @@
|
|
|
178
185
|
|
|
179
186
|
&.disabled {
|
|
180
187
|
color: var(--text-muted);
|
|
181
|
-
pointer-events: none;
|
|
182
188
|
opacity: 0.55;
|
|
189
|
+
cursor: not-allowed;
|
|
190
|
+
|
|
191
|
+
&:hover { background: transparent; color: var(--text-muted); }
|
|
183
192
|
}
|
|
184
193
|
|
|
185
194
|
.cny-sidebar-item-icon {
|
|
@@ -218,18 +227,8 @@
|
|
|
218
227
|
|
|
219
228
|
// Themed scrollbar for sidebar content
|
|
220
229
|
.cny-sidebar {
|
|
221
|
-
scrollbar-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
&::-webkit-scrollbar { width: 6px; }
|
|
225
|
-
&::-webkit-scrollbar-track { background: transparent; }
|
|
226
|
-
&::-webkit-scrollbar-thumb {
|
|
227
|
-
background: var(--border-color);
|
|
228
|
-
border-radius: 3px;
|
|
229
|
-
}
|
|
230
|
-
&::-webkit-scrollbar-thumb:hover {
|
|
231
|
-
background: var(--border-color-strong);
|
|
232
|
-
}
|
|
230
|
+
scrollbar-gutter: stable;
|
|
231
|
+
@include sb.expand-scrollbar;
|
|
233
232
|
}
|
|
234
233
|
|
|
235
234
|
// Collapsed variant: icons only
|
|
@@ -254,7 +253,7 @@
|
|
|
254
253
|
|
|
255
254
|
.cny-sidebar-item {
|
|
256
255
|
justify-content: center;
|
|
257
|
-
padding: 10px;
|
|
256
|
+
padding: 9px 10px;
|
|
258
257
|
// The collapsed rail centres its items, so undo the flush-left break-out.
|
|
259
258
|
margin-left: 0;
|
|
260
259
|
margin-right: 0;
|
|
@@ -286,6 +285,8 @@
|
|
|
286
285
|
z-index: 1001;
|
|
287
286
|
width: min(300px, 86vw);
|
|
288
287
|
max-height: none;
|
|
288
|
+
// an overlay: lift it off the page (and the dimmed backdrop) in dark
|
|
289
|
+
background: var(--bg-surface-lowest);
|
|
289
290
|
transform: translateX(-100%);
|
|
290
291
|
visibility: hidden;
|
|
291
292
|
transition: transform 220ms var(--ease-standard), visibility 0s linear 220ms;
|
|
@@ -312,6 +313,9 @@
|
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
.cny-dark .cny-sidebar-backdrop.open { background: rgba(0, 0, 0, 0.7); }
|
|
316
|
+
@media (prefers-color-scheme: dark) {
|
|
317
|
+
:root:not(.cny-light) .cny-sidebar-backdrop.open { background: rgba(0, 0, 0, 0.7); }
|
|
318
|
+
}
|
|
315
319
|
}
|
|
316
320
|
|
|
317
321
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
width: 60%;
|
|
37
37
|
border-radius: var(--radius-xs);
|
|
38
38
|
}
|
|
39
|
-
&.circle { border-radius: 50%; }
|
|
39
|
+
&.circle { border-radius: 50%; width: 32px; height: 32px; }
|
|
40
|
+
&.rect { width: 100%; height: 96px; border-radius: var(--radius-md); }
|
|
40
41
|
&.button { height: 36px; width: 96px; border-radius: var(--radius-sm); }
|
|
41
42
|
&.avatar { width: 32px; height: 32px; border-radius: 50%; }
|
|
42
43
|
}
|
|
@@ -70,3 +71,41 @@
|
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
74
|
+
|
|
75
|
+
// .cny-light wins over a dark OS preference
|
|
76
|
+
.cny-light .skeleton::after {
|
|
77
|
+
background: linear-gradient(
|
|
78
|
+
90deg,
|
|
79
|
+
transparent 0%,
|
|
80
|
+
rgba(255, 255, 255, 0.45) 50%,
|
|
81
|
+
transparent 100%
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Composite layouts
|
|
86
|
+
.skeleton-lines {
|
|
87
|
+
display: block;
|
|
88
|
+
width: 100%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.skeleton-card {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: 10px;
|
|
95
|
+
padding: 12px;
|
|
96
|
+
border: 1px solid var(--border-color);
|
|
97
|
+
border-radius: var(--radius-md);
|
|
98
|
+
background: var(--bg-surface-lowest);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.skeleton-list-item {
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
gap: 12px;
|
|
105
|
+
padding: 12px 14px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.skeleton-list-item-body {
|
|
109
|
+
flex: 1 1 auto;
|
|
110
|
+
min-width: 0;
|
|
111
|
+
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
&-track {
|
|
17
17
|
position: relative;
|
|
18
18
|
flex: 1;
|
|
19
|
-
background: var(--
|
|
19
|
+
background: var(--border-input); // rail >=3:1 against the page (WCAG 1.4.11)
|
|
20
20
|
border-radius: 999px;
|
|
21
21
|
height: 4px;
|
|
22
22
|
overflow: hidden;
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
&:hover { transform: scale(1.08); }
|
|
43
43
|
&:active { cursor: grabbing; }
|
|
44
44
|
&:focus-visible {
|
|
45
|
-
outline: 2px solid var(--
|
|
45
|
+
outline: 2px solid var(--border-focus);
|
|
46
46
|
outline-offset: 2px;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -68,6 +68,12 @@
|
|
|
68
68
|
&-thumb:focus-visible &-bubble,
|
|
69
69
|
&-thumb[data-state='active'] &-bubble { opacity: 1; }
|
|
70
70
|
|
|
71
|
+
// Value tooltip (`showValueTooltip`): only while dragging / keyboard-focused,
|
|
72
|
+
// never on plain hover.
|
|
73
|
+
&-tooltip { opacity: 0; }
|
|
74
|
+
&.is-dragging &-tooltip,
|
|
75
|
+
&-thumb:focus-visible &-tooltip { opacity: 1; }
|
|
76
|
+
|
|
71
77
|
&[data-disabled] {
|
|
72
78
|
opacity: 0.5;
|
|
73
79
|
.cny-slider-thumb { cursor: not-allowed; }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use '../base/scrollbar-mixin' as sb;
|
|
1
2
|
@use '../tokens/primitives' as *;
|
|
2
3
|
|
|
3
4
|
// Stepper — wizard / multi-step progress trail.
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
&:hover .cny-stepper-label { color: var(--text-primary); }
|
|
33
34
|
}
|
|
34
35
|
&:focus-visible {
|
|
35
|
-
outline: 2px solid var(--
|
|
36
|
+
outline: 2px solid var(--border-focus);
|
|
36
37
|
outline-offset: 2px;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -95,14 +96,26 @@
|
|
|
95
96
|
.cny-stepper-connector { background: var(--color-success); }
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
&-step.is-error {
|
|
100
|
+
.cny-stepper-marker {
|
|
101
|
+
background: var(--color-danger);
|
|
102
|
+
border-color: var(--color-danger);
|
|
103
|
+
color: var(--color-danger-on);
|
|
104
|
+
}
|
|
105
|
+
.cny-stepper-label { color: var(--color-danger-text); }
|
|
106
|
+
.cny-stepper-connector { background: var(--border-color); }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Horizontal — steps never shrink; a wide trail scrolls sideways instead of clipping.
|
|
99
110
|
&-horizontal {
|
|
100
111
|
display: flex;
|
|
101
112
|
align-items: center;
|
|
102
113
|
gap: $space-2;
|
|
114
|
+
overflow-x: auto;
|
|
115
|
+
@include sb.expand-scrollbar;
|
|
103
116
|
|
|
104
|
-
.cny-stepper-step { flex: 0
|
|
105
|
-
.cny-stepper-step:not(:last-child) { flex: 1
|
|
117
|
+
.cny-stepper-step { flex: 0 0 auto; }
|
|
118
|
+
.cny-stepper-step:not(:last-child) { flex: 1 0 auto; }
|
|
106
119
|
.cny-stepper-connector { height: 2px; margin: 0 $space-2; min-width: 12px; }
|
|
107
120
|
}
|
|
108
121
|
|
|
@@ -123,3 +136,8 @@
|
|
|
123
136
|
.cny-stepper-desc { font-size: 0.7rem; }
|
|
124
137
|
}
|
|
125
138
|
}
|
|
139
|
+
|
|
140
|
+
// Coarse pointers: each step is a >=44px target.
|
|
141
|
+
@media (pointer: coarse) {
|
|
142
|
+
.cny-stepper-step-row { min-height: 44px; }
|
|
143
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use '../base/scrollbar-mixin' as sb;
|
|
1
2
|
@use '../tokens/primitives' as *;
|
|
2
3
|
|
|
3
4
|
// Table — enterprise data tables. Opt-in .striped, .bordered, .compact.
|
|
@@ -34,9 +35,22 @@
|
|
|
34
35
|
&:last-child td { border-bottom: 0; }
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
&.striped tbody tr:nth-child(odd) { background: var(--bg-surface-low); }
|
|
39
|
+
|
|
40
|
+
// after .striped so hover wins on odd rows; on a striped table the hover tint
|
|
41
|
+
// is a step beyond the stripe, otherwise hovering an odd row shows nothing
|
|
37
42
|
&.hoverable tbody tr:hover { background: var(--bg-surface-low); }
|
|
43
|
+
&.striped.hoverable tbody tr:hover {
|
|
44
|
+
background: color-mix(in srgb, var(--color-primary) 9%, var(--bg-surface-low));
|
|
45
|
+
}
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
// Keep the header in view while the rows scroll. Needs a scrolling ancestor
|
|
48
|
+
// with a bounded height (e.g. `.table-wrap` with a `max-height`).
|
|
49
|
+
&.sticky-header thead th {
|
|
50
|
+
position: sticky;
|
|
51
|
+
top: 0;
|
|
52
|
+
z-index: 2;
|
|
53
|
+
}
|
|
40
54
|
|
|
41
55
|
&.compact {
|
|
42
56
|
th, td { padding: $space-2 $space-3; }
|
|
@@ -80,7 +94,7 @@
|
|
|
80
94
|
position: absolute;
|
|
81
95
|
top: 0;
|
|
82
96
|
right: 0;
|
|
83
|
-
width:
|
|
97
|
+
width: 12px;
|
|
84
98
|
height: 100%;
|
|
85
99
|
cursor: col-resize;
|
|
86
100
|
user-select: none;
|
|
@@ -89,11 +103,16 @@
|
|
|
89
103
|
background: transparent;
|
|
90
104
|
transition: background-color var(--transition-fast);
|
|
91
105
|
|
|
106
|
+
&:focus-visible {
|
|
107
|
+
outline: 2px solid var(--border-focus);
|
|
108
|
+
outline-offset: -2px;
|
|
109
|
+
}
|
|
110
|
+
|
|
92
111
|
&::after {
|
|
93
112
|
content: '';
|
|
94
113
|
position: absolute;
|
|
95
114
|
top: 20%;
|
|
96
|
-
right:
|
|
115
|
+
right: 5px;
|
|
97
116
|
width: 1px;
|
|
98
117
|
height: 60%;
|
|
99
118
|
background: var(--border-color);
|
|
@@ -123,6 +142,7 @@
|
|
|
123
142
|
// Wrapper for horizontal scroll on narrow viewports
|
|
124
143
|
.table-wrap {
|
|
125
144
|
overflow-x: auto;
|
|
145
|
+
@include sb.expand-scrollbar;
|
|
126
146
|
border: 1px solid var(--border-color);
|
|
127
147
|
border-radius: var(--radius-md);
|
|
128
148
|
background: var(--bg-surface-lowest);
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
&:hover { color: var(--text-secondary); }
|
|
50
50
|
&:focus-visible {
|
|
51
|
-
outline: 2px solid
|
|
51
|
+
outline: 2px solid var(--border-focus);
|
|
52
52
|
outline-offset: 2px;
|
|
53
53
|
border-radius: var(--radius-xs);
|
|
54
54
|
}
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
border-bottom: 2px solid transparent;
|
|
73
73
|
|
|
74
74
|
&[data-state='active'] {
|
|
75
|
-
color: var(--
|
|
75
|
+
color: var(--text-accent);
|
|
76
76
|
border-bottom-color: var(--color-primary);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
|
|
104
104
|
&:hover { background: var(--bg-surface-low); }
|
|
105
105
|
&[data-state='active'] {
|
|
106
|
-
color: var(--
|
|
106
|
+
color: var(--text-accent);
|
|
107
107
|
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -141,8 +141,124 @@
|
|
|
141
141
|
flex: 1 1 auto;
|
|
142
142
|
|
|
143
143
|
&:focus-visible {
|
|
144
|
-
outline: 2px solid var(--
|
|
144
|
+
outline: 2px solid var(--border-focus);
|
|
145
145
|
outline-offset: 2px;
|
|
146
146
|
border-radius: var(--radius-xs);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
// ── Sliding indicator (Tabs `indicator`) ──────────────────────
|
|
151
|
+
// The active trigger's own underline/fill is replaced by one element that
|
|
152
|
+
// slides to its position via --cny-tabs-x/y/w/h set from the measured tab.
|
|
153
|
+
.cny-tabs-indicator {
|
|
154
|
+
position: absolute;
|
|
155
|
+
left: 0;
|
|
156
|
+
top: 0;
|
|
157
|
+
pointer-events: none;
|
|
158
|
+
opacity: 0;
|
|
159
|
+
width: var(--cny-tabs-w, 0);
|
|
160
|
+
height: var(--cny-tabs-h, 0);
|
|
161
|
+
transform: translate(var(--cny-tabs-x, 0), var(--cny-tabs-y, 0));
|
|
162
|
+
transition: transform 220ms cubic-bezier(0.4, 0, 0.2, 1), width 220ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
163
|
+
height 220ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
164
|
+
&[data-ready] { opacity: 1; }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.cny-tabs.has-indicator {
|
|
168
|
+
.cny-tabs-trigger { position: relative; z-index: 1; }
|
|
169
|
+
|
|
170
|
+
&.variant-line {
|
|
171
|
+
.cny-tabs-trigger[data-state='active'] { border-bottom-color: transparent; border-right-color: transparent; }
|
|
172
|
+
.cny-tabs-indicator {
|
|
173
|
+
top: auto;
|
|
174
|
+
bottom: -1px;
|
|
175
|
+
height: 2px;
|
|
176
|
+
background: var(--color-primary);
|
|
177
|
+
transform: translateX(var(--cny-tabs-x, 0));
|
|
178
|
+
}
|
|
179
|
+
&[data-orientation='vertical'] .cny-tabs-indicator {
|
|
180
|
+
left: auto;
|
|
181
|
+
right: -1px;
|
|
182
|
+
top: 0;
|
|
183
|
+
bottom: auto;
|
|
184
|
+
width: 2px;
|
|
185
|
+
height: var(--cny-tabs-h, 0);
|
|
186
|
+
transform: translateY(var(--cny-tabs-y, 0));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
&.variant-pills {
|
|
190
|
+
.cny-tabs-trigger[data-state='active'] { background: transparent; }
|
|
191
|
+
.cny-tabs-indicator {
|
|
192
|
+
border-radius: 999px;
|
|
193
|
+
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
&.variant-segmented {
|
|
197
|
+
.cny-tabs-trigger[data-state='active'] { background: transparent; box-shadow: none; }
|
|
198
|
+
.cny-tabs-indicator {
|
|
199
|
+
border-radius: 999px;
|
|
200
|
+
background: var(--bg-surface-lowest);
|
|
201
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), inset 0 0 0 1px var(--hairline-color);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ── Scrolling list (Tabs `overflow="scroll"`) ─────────────────
|
|
207
|
+
.cny-tabs-scroller {
|
|
208
|
+
position: relative;
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: stretch;
|
|
211
|
+
min-width: 0;
|
|
212
|
+
|
|
213
|
+
.cny-tabs-list.is-scroll {
|
|
214
|
+
flex: 1 1 auto;
|
|
215
|
+
min-width: 0;
|
|
216
|
+
flex-wrap: nowrap;
|
|
217
|
+
overflow-x: auto;
|
|
218
|
+
scrollbar-width: none;
|
|
219
|
+
&::-webkit-scrollbar { display: none; }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Edge fades appear only on the side that has more content.
|
|
223
|
+
&[data-start] .cny-tabs-list.is-scroll { mask-image: linear-gradient(to right, transparent, #000 28px); }
|
|
224
|
+
&[data-end] .cny-tabs-list.is-scroll { mask-image: linear-gradient(to left, transparent, #000 28px); }
|
|
225
|
+
&[data-start][data-end] .cny-tabs-list.is-scroll {
|
|
226
|
+
mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.cny-tabs-arrow {
|
|
231
|
+
position: absolute;
|
|
232
|
+
top: 50%;
|
|
233
|
+
transform: translateY(-50%);
|
|
234
|
+
z-index: 2;
|
|
235
|
+
display: none;
|
|
236
|
+
align-items: center;
|
|
237
|
+
justify-content: center;
|
|
238
|
+
width: 24px;
|
|
239
|
+
height: 24px;
|
|
240
|
+
padding: 0;
|
|
241
|
+
border: 1px solid var(--hairline-color);
|
|
242
|
+
border-radius: 50%;
|
|
243
|
+
background: var(--bg-surface-lowest);
|
|
244
|
+
color: var(--text-secondary);
|
|
245
|
+
cursor: pointer;
|
|
246
|
+
&:hover { color: var(--text-primary); }
|
|
247
|
+
&.is-start { left: 0; }
|
|
248
|
+
&.is-end { right: 0; }
|
|
249
|
+
}
|
|
250
|
+
.cny-tabs-scroller[data-start] .cny-tabs-arrow.is-start,
|
|
251
|
+
.cny-tabs-scroller[data-end] .cny-tabs-arrow.is-end { display: inline-flex; }
|
|
252
|
+
|
|
253
|
+
@media (prefers-reduced-motion: reduce) {
|
|
254
|
+
.cny-tabs-indicator { transition: none; }
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Coarse pointers: >=44px triggers and scroll arrows.
|
|
258
|
+
@media (pointer: coarse) {
|
|
259
|
+
.cny-tabs-trigger { min-height: 44px; }
|
|
260
|
+
.cny-tabs-arrow {
|
|
261
|
+
width: 44px;
|
|
262
|
+
height: 44px;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use '../base/scrollbar-mixin' as sb;
|
|
1
2
|
@use '../tokens/primitives' as *;
|
|
2
3
|
|
|
3
4
|
// Timeline — activity / history rail.
|
|
@@ -87,6 +88,8 @@
|
|
|
87
88
|
|
|
88
89
|
&-soft {
|
|
89
90
|
background: var(--dot-soft);
|
|
91
|
+
// The soft tint alone vanishes against either page; a tinted rim keeps the dot findable.
|
|
92
|
+
border: 1.5px solid color-mix(in srgb, var(--dot-color) 55%, transparent);
|
|
90
93
|
color: var(--dot-color);
|
|
91
94
|
}
|
|
92
95
|
|
|
@@ -293,6 +296,15 @@
|
|
|
293
296
|
flex-direction: row;
|
|
294
297
|
align-items: flex-start;
|
|
295
298
|
width: 100%;
|
|
299
|
+
max-width: 100%;
|
|
300
|
+
// A wide rail scrolls inside itself rather than pushing the page sideways.
|
|
301
|
+
overflow-x: auto;
|
|
302
|
+
@include sb.expand-scrollbar;
|
|
303
|
+
|
|
304
|
+
&:focus-visible {
|
|
305
|
+
outline: 2px solid var(--border-focus);
|
|
306
|
+
outline-offset: 2px;
|
|
307
|
+
}
|
|
296
308
|
}
|
|
297
309
|
|
|
298
310
|
.cny-timeline-horizontal .cny-timeline-item {
|
|
@@ -366,3 +378,17 @@
|
|
|
366
378
|
padding: 0 $space-2 $space-2;
|
|
367
379
|
text-align: center;
|
|
368
380
|
}
|
|
381
|
+
|
|
382
|
+
// `navigable` focus ring, plus `empty` state
|
|
383
|
+
.cny-timeline-item:focus-visible {
|
|
384
|
+
outline: 2px solid var(--border-focus);
|
|
385
|
+
outline-offset: 2px;
|
|
386
|
+
border-radius: var(--radius-sm);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.cny-timeline-empty {
|
|
390
|
+
list-style: none;
|
|
391
|
+
padding: 16px 0;
|
|
392
|
+
font-size: 0.875rem;
|
|
393
|
+
color: var(--text-muted);
|
|
394
|
+
}
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
// ── Toast surface — flat white card ─────────────────────────────
|
|
62
62
|
.cny-toast {
|
|
63
63
|
--toast-accent: var(--color-primary);
|
|
64
|
+
--toast-accent-text: var(--text-accent);
|
|
64
65
|
|
|
65
66
|
position: relative;
|
|
66
67
|
display: flex;
|
|
@@ -75,23 +76,20 @@
|
|
|
75
76
|
color: var(--text-primary);
|
|
76
77
|
border: 1px solid color-mix(in srgb, var(--border-color) 60%, transparent);
|
|
77
78
|
border-radius: 10px;
|
|
78
|
-
box-shadow:
|
|
79
|
-
0 1px 2px rgba(15, 23, 42, 0.04),
|
|
80
|
-
0 8px 24px rgba(149, 157, 165, 0.18);
|
|
79
|
+
box-shadow: var(--shadow-popover);
|
|
81
80
|
font-family: var(--font-body);
|
|
82
81
|
font-size: 0.875rem;
|
|
83
82
|
line-height: 1.5;
|
|
84
83
|
overflow: hidden;
|
|
85
84
|
pointer-events: auto;
|
|
85
|
+
touch-action: pan-y; // vertical page scroll stays native; horizontal = swipe-to-dismiss
|
|
86
86
|
transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
87
87
|
box-shadow 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
88
88
|
animation: cny-toast-in-bottom 220ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
|
89
89
|
|
|
90
90
|
&:hover {
|
|
91
91
|
transform: translateY(-2px);
|
|
92
|
-
box-shadow:
|
|
93
|
-
0 1px 2px rgba(15, 23, 42, 0.04),
|
|
94
|
-
0 14px 32px rgba(149, 157, 165, 0.24);
|
|
92
|
+
box-shadow: var(--shadow-lg);
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
// Direction-aware entrance
|
|
@@ -113,11 +111,11 @@
|
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
// ── Variants — only --toast-accent shifts ──
|
|
116
|
-
&.success { --toast-accent: var(--color-success); }
|
|
117
|
-
&.info { --toast-accent: var(--color-info); }
|
|
118
|
-
&.warning { --toast-accent: var(--color-warning); }
|
|
119
|
-
&.danger { --toast-accent: var(--color-danger); }
|
|
120
|
-
&.loading { --toast-accent: var(--color-primary); }
|
|
114
|
+
&.success { --toast-accent: var(--color-success); --toast-accent-text: var(--color-success-text); }
|
|
115
|
+
&.info { --toast-accent: var(--color-info); --toast-accent-text: var(--color-info-text); }
|
|
116
|
+
&.warning { --toast-accent: var(--color-warning); --toast-accent-text: var(--color-warning-text); }
|
|
117
|
+
&.danger { --toast-accent: var(--color-danger); --toast-accent-text: var(--color-danger-text); }
|
|
118
|
+
&.loading { --toast-accent: var(--color-primary); --toast-accent-text: var(--text-accent); }
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
// ── Wave decoration on the left edge ─────────────────────────────
|
|
@@ -183,7 +181,7 @@
|
|
|
183
181
|
letter-spacing: -0.01em;
|
|
184
182
|
line-height: 1.25;
|
|
185
183
|
margin: 0;
|
|
186
|
-
color: var(--toast-accent);
|
|
184
|
+
color: var(--toast-accent-text);
|
|
187
185
|
font-size: 16px;
|
|
188
186
|
text-align: center;
|
|
189
187
|
cursor: default;
|
|
@@ -208,6 +206,20 @@
|
|
|
208
206
|
z-index: 1;
|
|
209
207
|
}
|
|
210
208
|
|
|
209
|
+
.cny-toast-action-btn {
|
|
210
|
+
padding: 4px 10px;
|
|
211
|
+
background: transparent;
|
|
212
|
+
border: 0;
|
|
213
|
+
border-radius: var(--radius-sm);
|
|
214
|
+
font: inherit;
|
|
215
|
+
font-weight: 650;
|
|
216
|
+
color: var(--toast-accent-text);
|
|
217
|
+
cursor: pointer;
|
|
218
|
+
transition: background-color 140ms ease;
|
|
219
|
+
&:hover { background: color-mix(in srgb, var(--toast-accent) 12%, transparent); }
|
|
220
|
+
&:focus-visible { outline: 2px solid var(--toast-accent); outline-offset: 2px; }
|
|
221
|
+
}
|
|
222
|
+
|
|
211
223
|
// ── Close button ───────────────────────────────────────────────
|
|
212
224
|
.cny-toast-close {
|
|
213
225
|
flex: none;
|
|
@@ -8,10 +8,16 @@
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
.cny-tooltip-content {
|
|
11
|
-
z-index: 1020;
|
|
11
|
+
z-index: var(--z-tooltip, 1020);
|
|
12
12
|
padding: 5px 9px;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// Light: inverted dark bubble. Dark: an elevated dark surface with a border —
|
|
14
|
+
// an inverted (white) bubble glares on a dark page.
|
|
15
|
+
--cny-tt-bg: var(--text-primary);
|
|
16
|
+
--cny-tt-fg: var(--bg-surface-lowest);
|
|
17
|
+
--cny-tt-border: transparent;
|
|
18
|
+
background: var(--cny-tt-bg);
|
|
19
|
+
color: var(--cny-tt-fg);
|
|
20
|
+
border: 1px solid var(--cny-tt-border);
|
|
15
21
|
border-radius: var(--radius-xs);
|
|
16
22
|
font-family: var(--font-body);
|
|
17
23
|
font-size: 0.75rem;
|
|
@@ -30,7 +36,22 @@
|
|
|
30
36
|
&[data-side='right'] { transform-origin: left center; }
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
.cny-
|
|
39
|
+
// Same trigger as the dark tokens: OS dark unless .cny-light, or an explicit .cny-dark.
|
|
40
|
+
@media (prefers-color-scheme: dark) {
|
|
41
|
+
:root:not(.cny-light) .cny-tooltip-content {
|
|
42
|
+
--cny-tt-bg: var(--bg-surface-edge);
|
|
43
|
+
--cny-tt-fg: var(--text-primary);
|
|
44
|
+
--cny-tt-border: var(--border-color-strong);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.cny-dark .cny-tooltip-content {
|
|
49
|
+
--cny-tt-bg: var(--bg-surface-edge);
|
|
50
|
+
--cny-tt-fg: var(--text-primary);
|
|
51
|
+
--cny-tt-border: var(--border-color-strong);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.cny-tooltip-arrow { fill: var(--cny-tt-bg, var(--text-primary)); }
|
|
34
55
|
|
|
35
56
|
@media (prefers-reduced-motion: reduce) {
|
|
36
57
|
.cny-tooltip-content { animation: none; }
|