@smwb/ui-styles 1.5.1 → 2.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/README.md +210 -12
- package/less/components/appBar/appBar.less +108 -0
- package/less/components/avatar/avatar.less +22 -0
- package/less/components/button/button.less +7 -1
- package/less/components/card/card.less +15 -4
- package/less/components/chart/chart.less +16 -15
- package/less/components/checkbox/checkbox.less +55 -4
- package/less/components/chip/chip.less +48 -3
- package/less/components/commandPalette/commandPalette.entry.less +2 -0
- package/less/components/commandPalette/commandPalette.less +233 -0
- package/less/components/composer/composer.entry.less +2 -0
- package/less/components/composer/composer.less +294 -0
- package/less/components/composer/composer.variables.less +10 -0
- package/less/components/dagView/dagView.entry.less +2 -0
- package/less/components/dagView/dagView.less +280 -0
- package/less/components/descriptionList/descriptionList.less +7 -1
- package/less/components/diffStat/diffStat.entry.less +2 -0
- package/less/components/diffStat/diffStat.less +76 -0
- package/less/components/kbd/kbd.entry.less +2 -0
- package/less/components/kbd/kbd.less +55 -0
- package/less/components/list/list.less +39 -0
- package/less/components/menu/menu.less +25 -1
- package/less/components/personChip/personChip.less +4 -2
- package/less/components/qrCode/qrCode.entry.less +2 -0
- package/less/components/qrCode/qrCode.less +35 -0
- package/less/components/radioButton/radioButton.less +46 -1
- package/less/components/rating/rating.less +15 -2
- package/less/components/selectField/selectField.less +87 -5
- package/less/components/sidebar/sidebar.less +26 -0
- package/less/components/statusDot/statusDot.entry.less +2 -0
- package/less/components/statusDot/statusDot.less +118 -0
- package/less/components/swimlanes/swimlanes.entry.less +2 -0
- package/less/components/swimlanes/swimlanes.less +126 -0
- package/less/components/tabGroups/tabGroups.entry.less +2 -0
- package/less/components/tabGroups/tabGroups.less +219 -0
- package/less/components/table/table.less +12 -0
- package/less/components/tabs/tab/tab.less +128 -0
- package/less/components/tabs/tabPanel/tabPanel.entry.less +2 -0
- package/less/components/tabs/tabPanel/tabPanel.less +8 -0
- package/less/components/tabs/tabs.less +26 -0
- package/less/components/textField/textField.less +34 -9
- package/less/components/thumbCard/thumbCard.less +12 -2
- package/less/components/toggle/toggle.less +42 -2
- package/less/components/treeView/treeView.less +40 -2
- package/less/components/typography/typography.less +13 -6
- package/less/components.less +10 -0
- package/less/connects/rt/table.less +7 -0
- package/less/default/globals/default.variables.less +152 -1
- package/less/foundation/sizing.less +41 -5
- package/less/foundation/typography.less +21 -0
- package/less/themes/material/variables.less +1 -0
- package/less/themes/summer/variables.less +1 -0
- package/less/variables.less +5 -0
- package/package.json +5 -2
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// Emits --smwb-dag-view-<name> from @dagView<Var><suffix> (suffix "" or "Dark").
|
|
2
|
+
// A variable that is `false` (the dark defaults) emits nothing, so the light
|
|
3
|
+
// value, a runtime token that follows the theme, stays in force.
|
|
4
|
+
.smwb-dag-view-token(@name; @var; @suffix) {
|
|
5
|
+
@full: ~"dagView@{var}@{suffix}";
|
|
6
|
+
.smwb-dag-view-token-value(@name; @@full);
|
|
7
|
+
}
|
|
8
|
+
.smwb-dag-view-token-value(@name; @value) when not (@value = false) {
|
|
9
|
+
--smwb-dag-view-@{name}: @value;
|
|
10
|
+
}
|
|
11
|
+
.smwb-dag-view-tokens(@suffix) {
|
|
12
|
+
.smwb-dag-view-token(node-bg; NodeBg; @suffix);
|
|
13
|
+
.smwb-dag-view-token(node-border; NodeBorder; @suffix);
|
|
14
|
+
.smwb-dag-view-token(edge-color; EdgeColor; @suffix);
|
|
15
|
+
.smwb-dag-view-token(edge-active-color; EdgeActiveColor; @suffix);
|
|
16
|
+
.smwb-dag-view-token(selected-ring; SelectedRing; @suffix);
|
|
17
|
+
.smwb-dag-view-token(status-idle; StatusIdle; @suffix);
|
|
18
|
+
.smwb-dag-view-token(status-pending; StatusPending; @suffix);
|
|
19
|
+
.smwb-dag-view-token(status-running; StatusRunning; @suffix);
|
|
20
|
+
.smwb-dag-view-token(status-success; StatusSuccess; @suffix);
|
|
21
|
+
.smwb-dag-view-token(status-warning; StatusWarning; @suffix);
|
|
22
|
+
.smwb-dag-view-token(status-error; StatusError; @suffix);
|
|
23
|
+
.smwb-dag-view-token(status-skipped; StatusSkipped; @suffix);
|
|
24
|
+
}
|
|
25
|
+
// A built-in status: its accent, unless the node sets its own.
|
|
26
|
+
.smwb-dag-view-status(@status) {
|
|
27
|
+
@accent: ~"var(--smwb-dag-view-node-accent, var(--smwb-dag-view-status-@{status}))";
|
|
28
|
+
&[data-status="@{status}"] {
|
|
29
|
+
--smwb-dag-view-accent: @accent;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// A dependency graph: a viewport that clips a "world" moved and scaled by one
|
|
34
|
+
// transform; in the world, an SVG layer of edges under absolutely placed nodes.
|
|
35
|
+
.smwb-dag-view {
|
|
36
|
+
.smwb-dag-view-tokens("");
|
|
37
|
+
--smwb-dag-view-dim-opacity: @dagViewDimOpacity;
|
|
38
|
+
|
|
39
|
+
position: relative;
|
|
40
|
+
width: 100%;
|
|
41
|
+
// The default height; the `height` prop or a height in `style` wins.
|
|
42
|
+
height: @dagViewHeight;
|
|
43
|
+
min-width: 0;
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
// clip, not hidden: a focused node off screen must not scroll the viewport
|
|
46
|
+
// (the view moves by its transform), and a clipping box is no Tab stop.
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
overflow: clip;
|
|
49
|
+
border: 1px solid var(--smui-dividerColor);
|
|
50
|
+
border-radius: @smui-radius-lg;
|
|
51
|
+
background-color: color-mix(in srgb, var(--smui-onSurfaceColor) 2%, var(--smui-surfaceBackground));
|
|
52
|
+
color: var(--smui-onSurfaceColor);
|
|
53
|
+
// The graph takes every touch gesture, and a wheel turn does not reach the page.
|
|
54
|
+
touch-action: none;
|
|
55
|
+
overscroll-behavior: contain;
|
|
56
|
+
user-select: none;
|
|
57
|
+
-webkit-user-select: none;
|
|
58
|
+
cursor: grab;
|
|
59
|
+
|
|
60
|
+
&[data-interacting] {
|
|
61
|
+
cursor: grabbing;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&__world {
|
|
65
|
+
position: absolute;
|
|
66
|
+
top: 0;
|
|
67
|
+
left: 0;
|
|
68
|
+
transform-origin: 0 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Only during a gesture: at rest it would blur the text.
|
|
72
|
+
&[data-interacting] &__world {
|
|
73
|
+
will-change: transform;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&__edges {
|
|
77
|
+
position: absolute;
|
|
78
|
+
top: 0;
|
|
79
|
+
left: 0;
|
|
80
|
+
overflow: visible;
|
|
81
|
+
pointer-events: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&__edge {
|
|
85
|
+
fill: none;
|
|
86
|
+
stroke: var(--smwb-dag-view-edge-color);
|
|
87
|
+
stroke-width: 1.5px;
|
|
88
|
+
transition:
|
|
89
|
+
stroke 0.12s,
|
|
90
|
+
opacity 0.12s;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&__edge--active {
|
|
94
|
+
stroke: var(--smwb-dag-view-edge-active-color);
|
|
95
|
+
stroke-width: 2.5px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// An edge that closes a cycle, drawn against the flow.
|
|
99
|
+
&__edge--reversed {
|
|
100
|
+
stroke-dasharray: 6 4;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&__edge--dimmed {
|
|
104
|
+
opacity: var(--smwb-dag-view-dim-opacity);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&__arrow {
|
|
108
|
+
fill: var(--smwb-dag-view-edge-color);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&__arrow--active {
|
|
112
|
+
fill: var(--smwb-dag-view-edge-active-color);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&__node {
|
|
116
|
+
--smwb-dag-view-accent: var(--smwb-dag-view-node-accent, var(--smwb-dag-view-status-idle));
|
|
117
|
+
.smwb-dag-view-status(pending);
|
|
118
|
+
.smwb-dag-view-status(running);
|
|
119
|
+
.smwb-dag-view-status(success);
|
|
120
|
+
.smwb-dag-view-status(warning);
|
|
121
|
+
.smwb-dag-view-status(error);
|
|
122
|
+
.smwb-dag-view-status(skipped);
|
|
123
|
+
|
|
124
|
+
position: absolute;
|
|
125
|
+
box-sizing: border-box;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: @smui-space-sm;
|
|
129
|
+
padding: 0 @smui-space-md 0 10px;
|
|
130
|
+
border: 1px solid var(--smwb-dag-view-node-border);
|
|
131
|
+
// The status stripe.
|
|
132
|
+
border-left: 4px solid var(--smwb-dag-view-accent);
|
|
133
|
+
border-radius: @smui-radius-md;
|
|
134
|
+
background-color: var(--smwb-dag-view-node-bg);
|
|
135
|
+
color: var(--smui-onSurfaceColor);
|
|
136
|
+
font-size: 0.875rem;
|
|
137
|
+
line-height: 1.3;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
contain: layout paint;
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
transition:
|
|
142
|
+
box-shadow 0.12s,
|
|
143
|
+
border-color 0.12s,
|
|
144
|
+
opacity 0.12s;
|
|
145
|
+
|
|
146
|
+
&:hover {
|
|
147
|
+
border-color: color-mix(in srgb, var(--smwb-dag-view-edge-active-color) 45%, var(--smwb-dag-view-node-border));
|
|
148
|
+
border-left-color: var(--smwb-dag-view-accent);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// normalize.css takes the outline off :focus; the keyboard gets a ring here.
|
|
152
|
+
&:focus-visible {
|
|
153
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
154
|
+
outline-offset: 2px;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&__node--selected {
|
|
159
|
+
box-shadow: 0 0 0 2px var(--smwb-dag-view-selected-ring);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
&__node--upstream,
|
|
163
|
+
&__node--downstream {
|
|
164
|
+
border-color: var(--smwb-dag-view-edge-active-color);
|
|
165
|
+
border-left-color: var(--smwb-dag-view-accent);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
&__node--dimmed {
|
|
169
|
+
opacity: var(--smwb-dag-view-dim-opacity);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
&__node--disabled {
|
|
173
|
+
cursor: default;
|
|
174
|
+
color: var(--smui-disabledTextColor);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
&__dot {
|
|
178
|
+
flex-shrink: 0;
|
|
179
|
+
width: 8px;
|
|
180
|
+
height: 8px;
|
|
181
|
+
border-radius: 50%;
|
|
182
|
+
background-color: var(--smwb-dag-view-accent);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&__label {
|
|
186
|
+
flex: 1 1 auto;
|
|
187
|
+
min-width: 0;
|
|
188
|
+
overflow: hidden;
|
|
189
|
+
font-weight: 500;
|
|
190
|
+
text-overflow: ellipsis;
|
|
191
|
+
white-space: nowrap;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
&__status {
|
|
195
|
+
flex-shrink: 0;
|
|
196
|
+
font-size: 0.75rem;
|
|
197
|
+
color: var(--smui-onSurfaceVariant);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Zoomed far out the status words (and any content marked __detail) give
|
|
201
|
+
// way, so the boxes stay readable.
|
|
202
|
+
&[data-zoom="far"] &__status,
|
|
203
|
+
&[data-zoom="far"] &__detail {
|
|
204
|
+
display: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// The graph in words, for screen readers only.
|
|
208
|
+
&__summary {
|
|
209
|
+
position: absolute;
|
|
210
|
+
width: 1px;
|
|
211
|
+
height: 1px;
|
|
212
|
+
margin: -1px;
|
|
213
|
+
padding: 0;
|
|
214
|
+
overflow: hidden;
|
|
215
|
+
clip: rect(0 0 0 0);
|
|
216
|
+
white-space: nowrap;
|
|
217
|
+
border: 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
&__controls {
|
|
221
|
+
position: absolute;
|
|
222
|
+
right: @smui-space-sm;
|
|
223
|
+
bottom: @smui-space-sm;
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
gap: @smui-space-xs;
|
|
227
|
+
cursor: default;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
&__control {
|
|
231
|
+
display: inline-flex;
|
|
232
|
+
align-items: center;
|
|
233
|
+
justify-content: center;
|
|
234
|
+
width: 32px;
|
|
235
|
+
height: 32px;
|
|
236
|
+
padding: 0;
|
|
237
|
+
border: 1px solid var(--smui-dividerColor);
|
|
238
|
+
border-radius: @smui-radius-md;
|
|
239
|
+
background-color: var(--smui-surfaceBackground);
|
|
240
|
+
color: var(--smui-onSurfaceVariant);
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
|
|
243
|
+
svg {
|
|
244
|
+
width: 18px;
|
|
245
|
+
height: 18px;
|
|
246
|
+
fill: none;
|
|
247
|
+
stroke: currentColor;
|
|
248
|
+
stroke-width: 2;
|
|
249
|
+
stroke-linecap: round;
|
|
250
|
+
stroke-linejoin: round;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
&:hover {
|
|
254
|
+
background-color: color-mix(in srgb, var(--smui-onSurfaceColor) 8%, var(--smui-surfaceBackground));
|
|
255
|
+
color: var(--smui-onSurfaceColor);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
&:focus-visible {
|
|
259
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
260
|
+
outline-offset: 2px;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
:root[data-theme="dark"] .smwb-dag-view {
|
|
266
|
+
.smwb-dag-view-tokens("Dark");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// A running node's dot pulses, unless motion is reduced.
|
|
270
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
271
|
+
.smwb-dag-view__node[data-status="running"] .smwb-dag-view__dot {
|
|
272
|
+
animation: smwb-dag-view-pulse 1.4s ease-in-out infinite;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@keyframes smwb-dag-view-pulse {
|
|
277
|
+
50% {
|
|
278
|
+
opacity: 0.35;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -39,7 +39,13 @@
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// auto: the list is its own query container, so its width — not the
|
|
42
|
-
// window's — decides when the pairs stack.
|
|
42
|
+
// window's — decides when the pairs stack. A container's content does not
|
|
43
|
+
// count toward its width, so where the parent takes its width from its
|
|
44
|
+
// content (a flex item that does not grow, a popover, a table cell) the list
|
|
45
|
+
// has none: it needs a width there, or "row" / "stacked". A fallback width
|
|
46
|
+
// (contain-intrinsic-inline-size) would also become the list's min-content
|
|
47
|
+
// width, and a card holding the list in a 1fr grid column or a flex: 1 item
|
|
48
|
+
// could no longer shrink below it.
|
|
43
49
|
&_auto {
|
|
44
50
|
container: smwb-description-list / inline-size;
|
|
45
51
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// The size of a change: "+N −M" (a U+2212 minus, not a hyphen), with an optional
|
|
2
|
+
// five-cell bar of the same proportions.
|
|
3
|
+
//
|
|
4
|
+
// Both the figures and their cells take the theme's success and error pulled
|
|
5
|
+
// @diffStatColorMix toward the surface ink. The raw tokens measure 3.89:1 (light)
|
|
6
|
+
// and 4.12–4.14:1 (dark) against the page — under the 4.5:1 text of this size
|
|
7
|
+
// needs — while the mix comes out 5.42:1 at worst across both themes and both
|
|
8
|
+
// backgrounds, and still clears the 3:1 a cell needs against a neutral one
|
|
9
|
+
// (WCAG 1.4.3 and 1.4.11). A cell nobody owns is an outline, not a fill: the surface
|
|
10
|
+
// ink mixed @diffStatNeutralMix into transparent measures 3.69:1 at worst (the material
|
|
11
|
+
// and summer light themes), 4.12:1 or better in the default light theme against the page
|
|
12
|
+
// and the surface and 5.4:1 or better in the dark ones, so "4 of 5" never looks like "5 of 5"; the tint
|
|
13
|
+
// the old track fill gave was 1.29:1 (default) and 1.08:1 (summer) against the page.
|
|
14
|
+
// No colour is written here: the ink is the theme's, so the dark theme follows on its own.
|
|
15
|
+
.smwb-diff-stat {
|
|
16
|
+
--smwb-diff-stat-added: ~"color-mix(in srgb, var(--smui-successColor) @{diffStatColorMix}, var(--smui-onSurfaceColor))";
|
|
17
|
+
--smwb-diff-stat-removed: ~"color-mix(in srgb, var(--smui-errorColor) @{diffStatColorMix}, var(--smui-onSurfaceColor))";
|
|
18
|
+
--smwb-diff-stat-neutral: ~"color-mix(in srgb, var(--smui-onSurfaceColor) @{diffStatNeutralMix}, transparent)";
|
|
19
|
+
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: @diffStatGap;
|
|
23
|
+
min-width: 0;
|
|
24
|
+
font-size: @diffStatFontSize;
|
|
25
|
+
line-height: 1.4;
|
|
26
|
+
font-variant-numeric: tabular-nums;
|
|
27
|
+
white-space: nowrap;
|
|
28
|
+
|
|
29
|
+
&__text {
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
gap: @diffStatSignGap;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__added {
|
|
36
|
+
color: var(--smwb-diff-stat-added);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&__removed {
|
|
40
|
+
color: var(--smwb-diff-stat-removed);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&__bar {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: @diffStatCellGap;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&__cell {
|
|
50
|
+
width: @diffStatCellWidth;
|
|
51
|
+
height: @diffStatCellHeight;
|
|
52
|
+
border-radius: @diffStatCellRadius;
|
|
53
|
+
// A border rather than a shadow, so the outline survives forced colours.
|
|
54
|
+
border: 1px solid var(--smwb-diff-stat-neutral);
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&__cell_added {
|
|
59
|
+
border-color: var(--smwb-diff-stat-added);
|
|
60
|
+
background-color: var(--smwb-diff-stat-added);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&__cell_removed {
|
|
64
|
+
border-color: var(--smwb-diff-stat-removed);
|
|
65
|
+
background-color: var(--smwb-diff-stat-removed);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// A tab label: the figures shrink and the cells with them.
|
|
69
|
+
&_compact {
|
|
70
|
+
font-size: @diffStatCompactFontSize;
|
|
71
|
+
|
|
72
|
+
.smwb-diff-stat__cell {
|
|
73
|
+
height: @diffStatCompactCellHeight;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// A keyboard shortcut: one small key cap per key. Everything is drawn from
|
|
2
|
+
// currentColor, so the same caps sit on a menu item, on the dark tooltip and in
|
|
3
|
+
// dark mode alike.
|
|
4
|
+
.smwb-kbd {
|
|
5
|
+
position: relative; // holds the visually hidden text
|
|
6
|
+
display: inline-flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
gap: @kbdGap;
|
|
9
|
+
flex-shrink: 0;
|
|
10
|
+
font-family: inherit;
|
|
11
|
+
font-size: inherit;
|
|
12
|
+
line-height: 1;
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
|
|
15
|
+
&__key {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
min-width: @kbdKeyMinSize;
|
|
21
|
+
height: @kbdKeyMinSize;
|
|
22
|
+
padding: 0 @kbdKeyPaddingX;
|
|
23
|
+
border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
|
|
24
|
+
border-radius: @kbdKeyRadius;
|
|
25
|
+
background-color: color-mix(in srgb, currentColor 10%, transparent);
|
|
26
|
+
font-family: inherit;
|
|
27
|
+
font-size: inherit;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
line-height: 1;
|
|
30
|
+
color: inherit;
|
|
31
|
+
user-select: none; // the caps repeat the hidden text: copy and find see the shortcut once
|
|
32
|
+
|
|
33
|
+
@media (forced-colors: active) {
|
|
34
|
+
border-color: currentColor;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__separator {
|
|
39
|
+
opacity: 0.7;
|
|
40
|
+
user-select: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The text assistive technology reads instead of the key caps.
|
|
44
|
+
&__text {
|
|
45
|
+
position: absolute;
|
|
46
|
+
width: 1px;
|
|
47
|
+
height: 1px;
|
|
48
|
+
margin: -1px;
|
|
49
|
+
padding: 0;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
clip: rect(0 0 0 0);
|
|
52
|
+
white-space: nowrap;
|
|
53
|
+
border: 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -75,6 +75,45 @@
|
|
|
75
75
|
padding-bottom: @smui-space-xs;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// A row that is a link: the anchor takes the padding, so the whole row is the link.
|
|
79
|
+
&__item.smwb-list__item_link,
|
|
80
|
+
&_dense &__item.smwb-list__item_link {
|
|
81
|
+
padding: 0;
|
|
82
|
+
gap: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// The end adornment sits beside the anchor, which has its own right padding: no end adornment, no part.
|
|
86
|
+
&__item_link > &__item__end {
|
|
87
|
+
padding-right: @smui-space-lg;
|
|
88
|
+
&:empty {
|
|
89
|
+
display: none;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&__item__link {
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
align-self: stretch;
|
|
97
|
+
flex: auto;
|
|
98
|
+
min-width: 0;
|
|
99
|
+
min-height: inherit;
|
|
100
|
+
box-sizing: border-box;
|
|
101
|
+
gap: @listItemGap;
|
|
102
|
+
padding: @listItemPadding;
|
|
103
|
+
color: inherit;
|
|
104
|
+
text-decoration: none;
|
|
105
|
+
&:focus-visible {
|
|
106
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
107
|
+
outline-offset: -2px;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&_dense &__item__link,
|
|
112
|
+
&__item_dense > &__item__link {
|
|
113
|
+
padding-top: @smui-space-xs;
|
|
114
|
+
padding-bottom: @smui-space-xs;
|
|
115
|
+
}
|
|
116
|
+
|
|
78
117
|
&__subheader {
|
|
79
118
|
padding: @smui-space-sm @smui-space-lg;
|
|
80
119
|
color: var(--smui-onSurfaceVariant);
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
white-space: nowrap;
|
|
29
29
|
height: 48px;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// A select's option the keys are on (aria-activedescendant, no DOM focus) keeps
|
|
32
|
+
// the focus layer under the pointer too, as a focused item does.
|
|
33
|
+
&:not(&--selected):not(:active):not(:focus-visible):not(.smwb-select-field__option--active) {
|
|
32
34
|
&:hover {
|
|
33
35
|
&:before {
|
|
34
36
|
opacity: @menuOpacityHover;
|
|
@@ -61,6 +63,23 @@
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// Keyboard focus: the focus state layer, over hover and the selected shade, and the
|
|
67
|
+
// library's ring, inside the item so that neither the menu's edge nor a scrolling menu
|
|
68
|
+
// clips it. normalize.css removes the browser's own ring.
|
|
69
|
+
&:focus-visible {
|
|
70
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
71
|
+
outline-offset: -2px;
|
|
72
|
+
|
|
73
|
+
&:before {
|
|
74
|
+
opacity: @menuOpacityFocus;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// An item with `href` takes focus a second time, on its link, which fills the item.
|
|
79
|
+
&:has(> &-inner:focus-visible):before {
|
|
80
|
+
opacity: @menuOpacityFocus;
|
|
81
|
+
}
|
|
82
|
+
|
|
64
83
|
&:active {
|
|
65
84
|
&:before {
|
|
66
85
|
opacity: @menuOpacityActive;
|
|
@@ -75,6 +94,11 @@
|
|
|
75
94
|
height: 100%;
|
|
76
95
|
color: currentColor;
|
|
77
96
|
gap: @menuItemGap;
|
|
97
|
+
|
|
98
|
+
&:focus-visible {
|
|
99
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
100
|
+
outline-offset: -2px;
|
|
101
|
+
}
|
|
78
102
|
}
|
|
79
103
|
|
|
80
104
|
&__text {
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
color: inherit;
|
|
11
11
|
text-decoration: none;
|
|
12
12
|
|
|
13
|
-
// The derived colours are mid-dark in both themes: white initials read on all
|
|
14
|
-
|
|
13
|
+
// The derived colours are mid-dark in both themes: white initials read on all
|
|
14
|
+
// of them. Two classes: the avatar's own colour rule (--smui-onPrimaryColor,
|
|
15
|
+
// dark in the dark theme) must not win on stylesheet order.
|
|
16
|
+
.smwb-avatar&__avatar {
|
|
15
17
|
flex-shrink: 0;
|
|
16
18
|
color: #fff;
|
|
17
19
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// A QR code of a value: an SVG image with dark modules on a white square — the quiet
|
|
2
|
+
// zone is part of the square, so the code scans on a dark page. The colours are fixed,
|
|
3
|
+
// never theme tokens, so no theme can invert the code; only the caption is themed.
|
|
4
|
+
.smwb-qr-code {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
align-items: center;
|
|
8
|
+
gap: @smui-space-sm;
|
|
9
|
+
margin: 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.smwb-qr-code__image {
|
|
13
|
+
// The rounded corner keeps the white square from looking pasted onto a dark page;
|
|
14
|
+
// the quiet zone keeps the modules clear of the rounding.
|
|
15
|
+
border-radius: @qrCodeRadius;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
// Forced colours would remap `fill` and could invert or flatten the code; printing
|
|
18
|
+
// would drop the dark modules.
|
|
19
|
+
forced-color-adjust: none;
|
|
20
|
+
print-color-adjust: exact;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.smwb-qr-code__light {
|
|
24
|
+
fill: @qrCodeLightColor;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.smwb-qr-code__dark {
|
|
28
|
+
fill: @qrCodeDarkColor;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.smwb-qr-code__caption {
|
|
32
|
+
color: var(--smui-onSurfaceVariant);
|
|
33
|
+
font-size: 0.8125rem;
|
|
34
|
+
text-align: center;
|
|
35
|
+
}
|
|
@@ -30,7 +30,20 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
&__input {
|
|
33
|
-
display: none
|
|
33
|
+
// Visually hidden but rendered: with display: none the input would be out of
|
|
34
|
+
// the tab order and the accessibility tree. It fills the wrapper, under the
|
|
35
|
+
// button, which takes the pointer and passes clicks on through the label.
|
|
36
|
+
position: absolute;
|
|
37
|
+
top: 0;
|
|
38
|
+
left: 0;
|
|
39
|
+
width: 100%;
|
|
40
|
+
height: 100%;
|
|
41
|
+
margin: 0;
|
|
42
|
+
opacity: 0;
|
|
43
|
+
&:focus-visible ~ .smwb-radio__btn {
|
|
44
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
45
|
+
outline-offset: 2px;
|
|
46
|
+
}
|
|
34
47
|
&:active {
|
|
35
48
|
& ~ .radio__btn:hover ~ .smwb-radio__bg {
|
|
36
49
|
transform: translate(-50%, -50%) scale(1);
|
|
@@ -127,6 +140,38 @@
|
|
|
127
140
|
pointer-events: none;
|
|
128
141
|
color: var(--smui-primaryTextColor);
|
|
129
142
|
}
|
|
143
|
+
|
|
144
|
+
// The size prop maps the row onto the control-height scale (the size class rides
|
|
145
|
+
// this component's root, which is the row). The box only moves off its current
|
|
146
|
+
// edge at sm and lg: radio's medium box is 20px today, not the 18px selection
|
|
147
|
+
// token, and re-tuning it would change every default RadioButton. So _size-medium
|
|
148
|
+
// sets the row height and leaves the box to the rule above — a documented
|
|
149
|
+
// exemption from @smui-selection-md. The 40px halo (__bg and __btn::before) is
|
|
150
|
+
// left unscaled with it, as the touch target is already below the row's own
|
|
151
|
+
// min-height.
|
|
152
|
+
&_size-small {
|
|
153
|
+
min-height: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
154
|
+
.smwb-radio__btn {
|
|
155
|
+
width: @smui-selection-sm;
|
|
156
|
+
height: @smui-selection-sm;
|
|
157
|
+
// 8px dot (not the base 10px): inside the 16px box's 2px border the
|
|
158
|
+
// fixed 10px dot would leave only a 1px ring.
|
|
159
|
+
&::after {
|
|
160
|
+
width: 8px;
|
|
161
|
+
height: 8px;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
&_size-medium {
|
|
166
|
+
min-height: var(--smui-control-h-md, @smui-control-h-md);
|
|
167
|
+
}
|
|
168
|
+
&_size-large {
|
|
169
|
+
min-height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
170
|
+
.smwb-radio__btn {
|
|
171
|
+
width: @smui-selection-lg;
|
|
172
|
+
height: @smui-selection-lg;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
130
175
|
}
|
|
131
176
|
|
|
132
177
|
@keyframes ping {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
// The control (the row of icons) with its helper text below it.
|
|
1
2
|
.smwb-rating {
|
|
2
3
|
display: inline-flex;
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: flex-start;
|
|
5
6
|
color: var(--smui-primaryColor);
|
|
6
7
|
|
|
7
8
|
&_disabled {
|
|
@@ -9,6 +10,18 @@
|
|
|
9
10
|
pointer-events: none;
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
&__control {
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: @ratingGap;
|
|
17
|
+
|
|
18
|
+
// normalize.css removes the browser's focus ring.
|
|
19
|
+
&:focus-visible {
|
|
20
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
21
|
+
outline-offset: 2px;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
12
25
|
&__item {
|
|
13
26
|
position: relative;
|
|
14
27
|
display: inline-flex;
|