@smwb/ui-styles 2.1.0 → 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/README.md +29 -10
- package/less/components/appBar/appBar.less +25 -3
- package/less/components/avatar/avatar.less +7 -0
- package/less/components/breadcrumbs/breadcrumbs.less +61 -0
- package/less/components/button/button.less +30 -0
- package/less/components/buttonGroup/buttonGroup.less +3 -2
- package/less/components/chip/chip.less +11 -0
- package/less/components/dagView/dagView.less +34 -1
- package/less/components/list/list.less +7 -0
- package/less/components/menu/menu.less +5 -0
- package/less/components/meter/meter.less +34 -0
- package/less/components/screenDivider/screenDivider.less +14 -6
- package/less/components/sheet/sheet.less +17 -7
- package/less/components/statusDot/statusDot.less +25 -0
- package/less/components/tabGroups/tabGroups.less +56 -3
- package/less/components/tabs/tab/tab.less +46 -0
- package/less/components/tabs/tabs.less +10 -0
- package/less/components/toggle/toggle.less +24 -0
- package/less/components/treeView/treeView.less +40 -17
- package/less/default/globals/default.variables.less +43 -0
- package/less/foundation/sizing.less +25 -0
- package/less/tokens.entry.less +7 -0
- package/less/variables.less +20 -0
- package/normalize.css +63 -73
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -101,6 +101,16 @@ tokens on its own root, so a value set on `:root` or a wrapper does not reach it
|
|
|
101
101
|
the matching `--smui-*Color` token (`default` is `--smui-onSurfaceVariant`). Its sizes are `@statusDotSizeSm`
|
|
102
102
|
(8px), `@statusDotSizeMd` (12px) and `@statusDotRing` (2px, the ring of `unknown`) in `theme.config`.
|
|
103
103
|
|
|
104
|
+
`shape="diamond"` reuses every one of those tokens: the colour and the ring are unchanged, and only the box is
|
|
105
|
+
derived. A square turned 45deg spans side × √2, so the diamond's side is the size over `@statusDotDiamondRatio`
|
|
106
|
+
(√2) — 8.4853px at `md`, 5.6569px at `sm` — which lands its bounding box back on the dot's 12px and 8px. A transform leaves the layout box at the unturned
|
|
107
|
+
side, so the rule adds a `margin` of half of (size − side) from the same tokens, and a label beside the diamond
|
|
108
|
+
stays where it is beside the dot. The turn
|
|
109
|
+
is `@statusDotDiamondRotation` (45deg) and the corners `@statusDotDiamondRadius` (`@smui-radius-none`), because the
|
|
110
|
+
dot's `border-radius: 50%` would otherwise survive the turn as a circle. Turning the box rather than clipping a
|
|
111
|
+
full-size one is what keeps `unknown` a real `@statusDotRing` border and lets the pulse's `::after` turn with its
|
|
112
|
+
parent. None of the three is a `--smui-*` runtime token, matching the dot's own sizes, which are compile-time too.
|
|
113
|
+
|
|
104
114
|
Against `--smui-surfaceBackground` and `--smui-pageBackground`, the default theme's status colours measure
|
|
105
115
|
at least 3:1 in both modes (the lowest is `attention` on the light surface, 3.04:1). The semantic colours are one
|
|
106
116
|
value for both modes, so a theme that makes `@warningColor` lighter, or any of them darker for the dark theme,
|
|
@@ -122,16 +132,18 @@ it, and the quiet zone keeps the modules clear of the rounding.
|
|
|
122
132
|
The dependency graph (`DagView` in `@smwb/ui-solid` and `@smwb/ui-react`) takes its colours from theme variables that default to the
|
|
123
133
|
runtime tokens, so the dark theme follows without extra settings:
|
|
124
134
|
|
|
125
|
-
| Variable (`theme.config`) | Runtime property on `.smwb-dag-view`
|
|
126
|
-
| ---------------------------------------------- |
|
|
127
|
-
| `@dagViewNodeBg` | `--smwb-dag-view-node-bg`
|
|
128
|
-
| `@dagViewNodeBorder` | `--smwb-dag-view-node-border`
|
|
129
|
-
| `@
|
|
130
|
-
| `@
|
|
131
|
-
| `@
|
|
132
|
-
| `@
|
|
133
|
-
| `@
|
|
134
|
-
| `@
|
|
135
|
+
| Variable (`theme.config`) | Runtime property on `.smwb-dag-view` | Default |
|
|
136
|
+
| ---------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
137
|
+
| `@dagViewNodeBg` | `--smwb-dag-view-node-bg` | `var(--smui-surfaceBackground)` |
|
|
138
|
+
| `@dagViewNodeBorder` | `--smwb-dag-view-node-border` | `var(--smui-outlineColor)` |
|
|
139
|
+
| `@dagViewNodeBorderStyle` | `--smwb-dag-view-node-border-style` | `solid` |
|
|
140
|
+
| `@dagViewStatusPendingBorderStyle` … `Skipped` | `--smwb-dag-view-status-pending-border-style` … `-skipped-border-style` | `false`: the node border style |
|
|
141
|
+
| `@dagViewEdgeColor` | `--smwb-dag-view-edge-color` | `var(--smui-outlineColor)` |
|
|
142
|
+
| `@dagViewEdgeActiveColor` | `--smwb-dag-view-edge-active-color` | `var(--smui-primaryColor)` |
|
|
143
|
+
| `@dagViewSelectedRing` | `--smwb-dag-view-selected-ring` | `var(--smui-primaryColor)` |
|
|
144
|
+
| `@dagViewStatusIdle` … `@dagViewStatusSkipped` | `--smwb-dag-view-status-idle` … `-skipped` | outline, on-surface variant, info, success, warning, error, disabled text |
|
|
145
|
+
| `@dagViewDimOpacity` | `--smwb-dag-view-dim-opacity` | `0.35` |
|
|
146
|
+
| `@dagViewHeight` | — (the graph's `height`) | `480px` |
|
|
135
147
|
|
|
136
148
|
The statuses are `idle`, `pending`, `running`, `success`, `warning`, `error` and `skipped`; a node with any other
|
|
137
149
|
status is drawn as `idle`. Each colour variable has a `…Dark` twin (e.g. `@dagViewStatusSuccessDark`), `false` by
|
|
@@ -144,6 +156,13 @@ node's accent comes from `--smwb-dag-view-accent`. For a status of your own, set
|
|
|
144
156
|
The graph's default height, `@dagViewHeight`, is set by the stylesheet, so its `height` prop or a height in its
|
|
145
157
|
`style` wins over it.
|
|
146
158
|
|
|
159
|
+
The node frame's line style is `@dagViewNodeBorderStyle` (`solid`): a theme that sets it to `dashed` dashes every
|
|
160
|
+
node. To dash only some nodes, set `@dagViewStatusWarningBorderStyle: dashed` (a status variable per built-in status
|
|
161
|
+
except `idle`; `false`, the default, follows the theme-wide style), or give a node `variant: "dashed"` (`"solid"`
|
|
162
|
+
keeps it solid under a dashed theme): the node's own variant outranks its status, and the status outranks the theme.
|
|
163
|
+
One `border-style` draws all four sides, so the status stripe on the left dashes too and the node reads as one
|
|
164
|
+
frame, not a frame inside a frame. The border style has no `…Dark` twin: it is not a colour.
|
|
165
|
+
|
|
147
166
|
#### Swimlanes
|
|
148
167
|
|
|
149
168
|
`Swimlanes` (in `@smwb/ui-react` and `@smwb/ui-solid`) reads only runtime tokens, so the dark theme follows without
|
|
@@ -123,35 +123,57 @@
|
|
|
123
123
|
calc(@appBarPaddingX + var(--smwb-appbar-wc-left));
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
// The bar is a flex row itself: without `min-width: 0` the inner row would not shrink below its content
|
|
127
|
+
// and a long title would push the right group past the bar's edge.
|
|
126
128
|
&__inner {
|
|
127
129
|
display: flex;
|
|
128
130
|
align-items: center;
|
|
129
131
|
width: 100%;
|
|
132
|
+
min-width: 0;
|
|
130
133
|
justify-content: space-between;
|
|
131
134
|
flex-wrap: nowrap;
|
|
132
135
|
}
|
|
136
|
+
// Room is given out in this order: the right group keeps its content size, the middle takes what is
|
|
137
|
+
// left over (and is the first to give it up), and only when even that is gone the title gives way.
|
|
133
138
|
&__left {
|
|
134
139
|
display: flex;
|
|
135
140
|
align-items: center;
|
|
136
141
|
gap: @appBarActionsGap;
|
|
137
142
|
white-space: nowrap;
|
|
143
|
+
flex: 0 1 auto;
|
|
144
|
+
min-width: 0;
|
|
138
145
|
}
|
|
139
146
|
// The title may be a heading (`titleAs`): drop the UA margins and font so it
|
|
140
|
-
// looks the same as the div.
|
|
147
|
+
// looks the same as the div. When the bar is too narrow for it, it is cut with an ellipsis.
|
|
148
|
+
// clip with a margin, not hidden: a control in the title (a link, a button) keeps its focus ring, which
|
|
149
|
+
// paints outside the box. `hidden` stays first for engines that know no `overflow: clip`.
|
|
141
150
|
&__left__title {
|
|
142
151
|
margin: 0;
|
|
143
152
|
font: inherit;
|
|
153
|
+
min-width: 0;
|
|
154
|
+
overflow: hidden;
|
|
155
|
+
overflow: clip;
|
|
156
|
+
overflow-clip-margin: @appBarClipMargin;
|
|
157
|
+
text-overflow: ellipsis;
|
|
144
158
|
}
|
|
145
159
|
&__right {
|
|
146
160
|
white-space: nowrap;
|
|
161
|
+
flex: 0 0 auto;
|
|
147
162
|
}
|
|
163
|
+
// The basis is 0, not `auto` with `width: 100%`: the middle grows into the free space instead of
|
|
164
|
+
// claiming the whole bar as its basis and taking its share of a shortfall from the title and the right group.
|
|
148
165
|
&__mid {
|
|
149
|
-
width: 100%;
|
|
150
166
|
display: flex;
|
|
151
|
-
flex: 1 1
|
|
167
|
+
flex: 1 1 0;
|
|
168
|
+
min-width: 0;
|
|
152
169
|
flex-direction: column;
|
|
153
170
|
flex-wrap: nowrap;
|
|
154
171
|
|
|
172
|
+
// A field wider than the room left to the middle narrows with it instead of running under the right group.
|
|
173
|
+
> * {
|
|
174
|
+
max-width: 100%;
|
|
175
|
+
}
|
|
176
|
+
|
|
155
177
|
&.smwb-middle {
|
|
156
178
|
align-items: center;
|
|
157
179
|
}
|
|
@@ -37,6 +37,13 @@
|
|
|
37
37
|
border-radius: 0;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// An image is drawn on the page, not on the fill: a transparent PNG/SVG shows
|
|
41
|
+
// what is behind the avatar. The fill stays under the fallback (initials, an
|
|
42
|
+
// icon), also after the image failed to load: the class goes with the image.
|
|
43
|
+
&_image {
|
|
44
|
+
background-color: transparent;
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
&__img {
|
|
41
48
|
width: 100%;
|
|
42
49
|
height: 100%;
|
|
@@ -54,4 +54,65 @@
|
|
|
54
54
|
background-color: var(--smui-onSurfaceActive);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
// One line: the list never wraps, the crumbs shrink and cut their text with an
|
|
59
|
+
// ellipsis, the leading ones first and down to a floor, and the trailing crumb
|
|
60
|
+
// (the page's own title) only after them. Below the sum of the floors the trail
|
|
61
|
+
// keeps them and runs past its box instead of squeezing a crumb to nothing.
|
|
62
|
+
&--no-wrap {
|
|
63
|
+
min-width: 0;
|
|
64
|
+
|
|
65
|
+
.smwb-breadcrumbs__list {
|
|
66
|
+
flex-wrap: nowrap;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// `text-overflow` reaches only the inline text of the box it sits on, so a block child (a
|
|
70
|
+
// heading, Typography) is cut by its own rule, and the crumb's own cuts what is inline in it.
|
|
71
|
+
// Clip with a margin, not hidden: a link or the expand button keeps its focus ring, which
|
|
72
|
+
// paints outside the box. `hidden` stays first for engines that know no `overflow: clip`.
|
|
73
|
+
.smwb-breadcrumbs__item,
|
|
74
|
+
.smwb-breadcrumbs__item > * {
|
|
75
|
+
min-width: 0;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
overflow: clip;
|
|
78
|
+
overflow-clip-margin: @breadcrumbsClipMargin;
|
|
79
|
+
text-overflow: ellipsis;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.smwb-breadcrumbs__item {
|
|
84
|
+
display: block;
|
|
85
|
+
flex: 0 1 auto;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.smwb-breadcrumbs__item > * {
|
|
89
|
+
max-width: 100%;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// A link is a box of its own, so it is cut there and its focus ring wraps what is shown
|
|
93
|
+
// instead of the whole text running out of the crumb.
|
|
94
|
+
.smwb-breadcrumbs__item > a {
|
|
95
|
+
display: inline-block;
|
|
96
|
+
vertical-align: top;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.smwb-breadcrumbs__item:not(:last-child) {
|
|
100
|
+
flex-shrink: @breadcrumbsLeadingShrink;
|
|
101
|
+
min-width: @breadcrumbsLeadingMinWidth;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.smwb-breadcrumbs__item:last-child {
|
|
105
|
+
min-width: @breadcrumbsLastMinWidth;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The expand button is not text: it keeps its size instead of taking the floor.
|
|
109
|
+
.smwb-breadcrumbs__item:has(> .smwb-breadcrumbs__expand) {
|
|
110
|
+
flex: none;
|
|
111
|
+
min-width: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.smwb-breadcrumbs__separator {
|
|
115
|
+
flex: none;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
57
118
|
}
|
|
@@ -46,6 +46,36 @@
|
|
|
46
46
|
min-height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Icon-only: a square of the size's control height. The width and the height both come from the
|
|
50
|
+
// same token, the padding is gone and min-width with it, so the icon sits in the middle and
|
|
51
|
+
// the box is the same for every variant and for a link. It wins over full-width on purpose.
|
|
52
|
+
// border-box: a <button> has it from the user agent, an <a> only from a reset, and the outlined
|
|
53
|
+
// border would otherwise add 2px to the link. The corners keep the button's own radius, capped
|
|
54
|
+
// by @buttonIconOnlyMaxBorderRadius so a pill button does not turn into a circle unless the theme asks.
|
|
55
|
+
&.smwb-button_icon-only {
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
min-width: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
flex: none;
|
|
60
|
+
border-radius: min(@buttonBorderRadius, @buttonIconOnlyMaxBorderRadius);
|
|
61
|
+
&:focus-visible {
|
|
62
|
+
outline: 2px solid var(--smui-primaryColor);
|
|
63
|
+
outline-offset: 2px;
|
|
64
|
+
}
|
|
65
|
+
&.smwb-small {
|
|
66
|
+
width: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
67
|
+
height: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
68
|
+
}
|
|
69
|
+
&.smwb-medium {
|
|
70
|
+
width: var(--smui-control-h-md, @smui-control-h-md);
|
|
71
|
+
height: var(--smui-control-h-md, @smui-control-h-md);
|
|
72
|
+
}
|
|
73
|
+
&.smwb-large {
|
|
74
|
+
width: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
75
|
+
height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
49
79
|
&.smwb-contained {
|
|
50
80
|
color: var(--smui-onPrimaryColor);
|
|
51
81
|
.smui-elevation(2);
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
box-shadow: none;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// Bound to the group itself: ScreenDivider also puts a bare orientation class on its wrapper and panes.
|
|
26
|
+
.smwb-button-group.smwb-horizontal > & {
|
|
26
27
|
&:not(:first-of-type) {
|
|
27
28
|
border-top-left-radius: 0;
|
|
28
29
|
border-bottom-left-radius: 0;
|
|
@@ -57,7 +58,7 @@
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
.smwb-vertical & {
|
|
61
|
+
.smwb-button-group.smwb-vertical > & {
|
|
61
62
|
&:not(:first-of-type) {
|
|
62
63
|
border-top-right-radius: 0;
|
|
63
64
|
border-top-left-radius: 0;
|
|
@@ -134,6 +134,17 @@
|
|
|
134
134
|
min-height: 24px;
|
|
135
135
|
padding: 0 @smui-space-sm;
|
|
136
136
|
font-size: 0.75rem;
|
|
137
|
+
|
|
138
|
+
// On a coarse pointer a small chip that is a button or a link is as tall as the sm step
|
|
139
|
+
// (44px there): its content is the button (the link is the box itself), and the box is
|
|
140
|
+
// what a finger has to hit. A small chip that only labels, or only deletes, stays 24px.
|
|
141
|
+
@media (pointer: coarse) {
|
|
142
|
+
&:is(a[href]),
|
|
143
|
+
&:has(> .smwb-chip__content[role="button"]) {
|
|
144
|
+
height: var(--smui-control-h-sm, @smui-control-h-sm-coarse);
|
|
145
|
+
min-height: var(--smui-control-h-sm, @smui-control-h-sm-coarse);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
137
148
|
}
|
|
138
149
|
|
|
139
150
|
// A color repaints the neutral filled/outlined rules above. The guard mirrors
|
|
@@ -22,11 +22,24 @@
|
|
|
22
22
|
.smwb-dag-view-token(status-error; StatusError; @suffix);
|
|
23
23
|
.smwb-dag-view-token(status-skipped; StatusSkipped; @suffix);
|
|
24
24
|
}
|
|
25
|
-
//
|
|
25
|
+
// The line style of the node frame, theme-wide and per built-in status. The status
|
|
26
|
+
// ones are `false` by default: they emit nothing, so the node falls back to the
|
|
27
|
+
// theme-wide one.
|
|
28
|
+
.smwb-dag-view-border-style(@status; @var) {
|
|
29
|
+
@full: ~"dagViewStatus@{var}BorderStyle";
|
|
30
|
+
.smwb-dag-view-border-style-value(@status; @@full);
|
|
31
|
+
}
|
|
32
|
+
.smwb-dag-view-border-style-value(@status; @value) when not (@value = false) {
|
|
33
|
+
--smwb-dag-view-status-@{status}-border-style: @value;
|
|
34
|
+
}
|
|
35
|
+
// A built-in status: its accent, unless the node sets its own, and its frame line
|
|
36
|
+
// style, unless the theme gives it none.
|
|
26
37
|
.smwb-dag-view-status(@status) {
|
|
27
38
|
@accent: ~"var(--smwb-dag-view-node-accent, var(--smwb-dag-view-status-@{status}))";
|
|
39
|
+
@style: ~"var(--smwb-dag-view-status-@{status}-border-style, var(--smwb-dag-view-node-border-style))";
|
|
28
40
|
&[data-status="@{status}"] {
|
|
29
41
|
--smwb-dag-view-accent: @accent;
|
|
42
|
+
--smwb-dag-view-border-style: @style;
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
|
|
@@ -35,6 +48,13 @@
|
|
|
35
48
|
.smwb-dag-view {
|
|
36
49
|
.smwb-dag-view-tokens("");
|
|
37
50
|
--smwb-dag-view-dim-opacity: @dagViewDimOpacity;
|
|
51
|
+
--smwb-dag-view-node-border-style: @dagViewNodeBorderStyle;
|
|
52
|
+
.smwb-dag-view-border-style(pending; Pending);
|
|
53
|
+
.smwb-dag-view-border-style(running; Running);
|
|
54
|
+
.smwb-dag-view-border-style(success; Success);
|
|
55
|
+
.smwb-dag-view-border-style(warning; Warning);
|
|
56
|
+
.smwb-dag-view-border-style(error; Error);
|
|
57
|
+
.smwb-dag-view-border-style(skipped; Skipped);
|
|
38
58
|
|
|
39
59
|
position: relative;
|
|
40
60
|
width: 100%;
|
|
@@ -120,6 +140,10 @@
|
|
|
120
140
|
.smwb-dag-view-status(warning);
|
|
121
141
|
.smwb-dag-view-status(error);
|
|
122
142
|
.smwb-dag-view-status(skipped);
|
|
143
|
+
// The frame's line style; a node's own `variant` outranks the status and the theme.
|
|
144
|
+
// One `border-style` draws all four sides, the stripe included, so a dashed node
|
|
145
|
+
// is one frame, not a frame inside a frame.
|
|
146
|
+
--smwb-dag-view-border-style: var(--smwb-dag-view-node-border-style);
|
|
123
147
|
|
|
124
148
|
position: absolute;
|
|
125
149
|
box-sizing: border-box;
|
|
@@ -130,6 +154,7 @@
|
|
|
130
154
|
border: 1px solid var(--smwb-dag-view-node-border);
|
|
131
155
|
// The status stripe.
|
|
132
156
|
border-left: 4px solid var(--smwb-dag-view-accent);
|
|
157
|
+
border-style: var(--smwb-dag-view-border-style);
|
|
133
158
|
border-radius: @smui-radius-md;
|
|
134
159
|
background-color: var(--smwb-dag-view-node-bg);
|
|
135
160
|
color: var(--smui-onSurfaceColor);
|
|
@@ -143,6 +168,14 @@
|
|
|
143
168
|
border-color 0.12s,
|
|
144
169
|
opacity 0.12s;
|
|
145
170
|
|
|
171
|
+
&[data-variant="solid"] {
|
|
172
|
+
--smwb-dag-view-border-style: solid;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
&[data-variant="dashed"] {
|
|
176
|
+
--smwb-dag-view-border-style: dashed;
|
|
177
|
+
}
|
|
178
|
+
|
|
146
179
|
&:hover {
|
|
147
180
|
border-color: color-mix(in srgb, var(--smwb-dag-view-edge-active-color) 45%, var(--smwb-dag-view-node-border));
|
|
148
181
|
border-left-color: var(--smwb-dag-view-accent);
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
min-height: 36px;
|
|
63
63
|
padding-top: @smui-space-xs;
|
|
64
64
|
padding-bottom: @smui-space-xs;
|
|
65
|
+
@media (pointer: coarse) {
|
|
66
|
+
min-height: max(36px, var(--smui-control-h-sm, @smui-control-h-sm-coarse));
|
|
67
|
+
}
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
&_divider {
|
|
@@ -73,6 +76,10 @@
|
|
|
73
76
|
min-height: 36px;
|
|
74
77
|
padding-top: @smui-space-xs;
|
|
75
78
|
padding-bottom: @smui-space-xs;
|
|
79
|
+
// On a coarse pointer a dense row is the sm step (44px there) at least.
|
|
80
|
+
@media (pointer: coarse) {
|
|
81
|
+
min-height: max(36px, var(--smui-control-h-sm, @smui-control-h-sm-coarse));
|
|
82
|
+
}
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
// A row that is a link: the anchor takes the padding, so the whole row is the link.
|
|
@@ -40,10 +40,44 @@
|
|
|
40
40
|
color: var(--smui-onSurfaceVariant);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// The text before the bar: it takes the first column, the bar the flexible one.
|
|
44
|
+
&_text-before {
|
|
45
|
+
grid-template-columns: auto minmax(@meterMinBarWidth, 1fr);
|
|
46
|
+
|
|
47
|
+
.smwb-meter__text {
|
|
48
|
+
order: -1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Compact: a fixed-width bar and small secondary text; the block shrinks to its
|
|
53
|
+
// content instead of filling the parent.
|
|
54
|
+
&_compact {
|
|
55
|
+
grid-template-columns: @meterCompactBarWidth auto;
|
|
56
|
+
width: fit-content;
|
|
57
|
+
max-width: 100%;
|
|
58
|
+
font-size: 0.75rem;
|
|
59
|
+
|
|
60
|
+
.smwb-meter__track {
|
|
61
|
+
height: @meterCompactHeight;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.smwb-meter__text {
|
|
65
|
+
color: var(--smui-onSurfaceVariant);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&_compact&_text-before {
|
|
70
|
+
grid-template-columns: auto @meterCompactBarWidth;
|
|
71
|
+
}
|
|
72
|
+
|
|
43
73
|
&_bar-only {
|
|
44
74
|
grid-template-columns: minmax(@meterMinBarWidth, 1fr);
|
|
45
75
|
}
|
|
46
76
|
|
|
77
|
+
&_compact&_bar-only {
|
|
78
|
+
grid-template-columns: @meterCompactBarWidth;
|
|
79
|
+
}
|
|
80
|
+
|
|
47
81
|
&_color-neutral {
|
|
48
82
|
--smwb-meter-color: var(--smui-onSurfaceVariant);
|
|
49
83
|
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
&.smwb-vertical {
|
|
8
8
|
flex-direction: column;
|
|
9
|
-
.
|
|
9
|
+
// A child, not a descendant: a divider nested in a pane keeps its own orientation's resizer.
|
|
10
|
+
> .smwb-screen-divider__resizer {
|
|
10
11
|
border-top: thin solid var(--smui-primaryColor);
|
|
11
12
|
border-bottom: thin solid var(--smui-primaryColor);
|
|
12
13
|
border-left: none;
|
|
@@ -42,15 +43,22 @@
|
|
|
42
43
|
content: "......";
|
|
43
44
|
text-align: center;
|
|
44
45
|
}
|
|
46
|
+
// A collapsed divider has no bar to see or drag: the other pane takes the whole wrapper.
|
|
47
|
+
&[hidden] {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
|
-
&__first
|
|
47
|
-
min-height: 5px;
|
|
48
|
-
min-width: 5px;
|
|
49
|
-
flex-shrink: 1;
|
|
50
|
-
}
|
|
51
|
+
&__first,
|
|
51
52
|
&__second {
|
|
52
53
|
min-height: 5px;
|
|
53
54
|
min-width: 5px;
|
|
54
55
|
flex-shrink: 1;
|
|
56
|
+
// A folded pane stays mounted but has no size, shows nothing and takes no focus.
|
|
57
|
+
&.smwb-collapsed {
|
|
58
|
+
min-height: 0;
|
|
59
|
+
min-width: 0;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
visibility: hidden;
|
|
62
|
+
}
|
|
55
63
|
}
|
|
56
64
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
.smwb-sheet {
|
|
2
|
+
// Gap between the top edge of the window and the top of the sheet and of its modal scrim. `Sheet`
|
|
3
|
+
// sets it from its `offsetTop` prop and `AppLayout` publishes its sticky header's height as the
|
|
4
|
+
// page default, so a panel starts below the header; with neither it is 0 and nothing moves.
|
|
5
|
+
@sheetOffsetTop: var(--smui-sheet-offset-top, 0px);
|
|
6
|
+
|
|
2
7
|
background-color: var(--smui-surfaceBackground);
|
|
3
8
|
position: fixed;
|
|
4
9
|
opacity: 0;
|
|
@@ -129,10 +134,12 @@
|
|
|
129
134
|
|
|
130
135
|
&.smwb-top {
|
|
131
136
|
border-radius: 0 0 @sheetBorderRadius @sheetBorderRadius;
|
|
132
|
-
top:
|
|
137
|
+
top: @sheetOffsetTop;
|
|
133
138
|
left: 0;
|
|
134
139
|
width: 100%;
|
|
135
140
|
height: var(--sizeProp);
|
|
141
|
+
// A tall panel stops at the bottom of the window instead of running past it by the offset.
|
|
142
|
+
max-height: calc(100% - @sheetOffsetTop);
|
|
136
143
|
transform: translateY(-100%);
|
|
137
144
|
flex-direction: column;
|
|
138
145
|
.smwb-sheet__header {
|
|
@@ -142,9 +149,9 @@
|
|
|
142
149
|
|
|
143
150
|
&.smwb-left {
|
|
144
151
|
border-radius: 0 @sheetBorderRadius @sheetBorderRadius 0;
|
|
145
|
-
top:
|
|
152
|
+
top: @sheetOffsetTop;
|
|
146
153
|
left: 0;
|
|
147
|
-
height: 100
|
|
154
|
+
height: calc(100% - @sheetOffsetTop);
|
|
148
155
|
width: var(--sizeProp);
|
|
149
156
|
transform: translateX(-100%);
|
|
150
157
|
flex-direction: row-reverse;
|
|
@@ -157,9 +164,9 @@
|
|
|
157
164
|
|
|
158
165
|
&.smwb-right {
|
|
159
166
|
border-radius: @sheetBorderRadius 0 0 @sheetBorderRadius;
|
|
160
|
-
top:
|
|
167
|
+
top: @sheetOffsetTop;
|
|
161
168
|
right: 0;
|
|
162
|
-
height: 100
|
|
169
|
+
height: calc(100% - @sheetOffsetTop);
|
|
163
170
|
width: var(--sizeProp);
|
|
164
171
|
transform: translateX(100%);
|
|
165
172
|
.smwb-sheet__header {
|
|
@@ -170,15 +177,18 @@
|
|
|
170
177
|
|
|
171
178
|
&__overlay {
|
|
172
179
|
position: fixed;
|
|
173
|
-
top:
|
|
180
|
+
top: @sheetOffsetTop;
|
|
174
181
|
left: 0;
|
|
175
182
|
width: 100%;
|
|
176
|
-
height: 100
|
|
183
|
+
height: calc(100% - @sheetOffsetTop);
|
|
177
184
|
display: flex;
|
|
178
185
|
flex-direction: column;
|
|
179
186
|
z-index: 100;
|
|
180
187
|
opacity: 0;
|
|
181
188
|
transition: all 0.25s ease-in-out;
|
|
189
|
+
// The panel slides in from beyond an edge of the scrim; clipped to the scrim, a panel sliding down from the top
|
|
190
|
+
// does not cross the header above it.
|
|
191
|
+
clip-path: inset(0);
|
|
182
192
|
&.smwb-entered {
|
|
183
193
|
opacity: 1;
|
|
184
194
|
}
|
|
@@ -18,6 +18,31 @@
|
|
|
18
18
|
height: @statusDotSizeSm;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// A diamond is the same marker turned corner-up. Its side is the dot's size over
|
|
22
|
+
// sqrt(2), so the turned square spans exactly the dot's box and the two shapes sit in
|
|
23
|
+
// one another's place. Turning the box, rather than clipping a full-size one, is what
|
|
24
|
+
// keeps the statuses readable: the `unknown` ring stays a real border of
|
|
25
|
+
// @statusDotRing, and the pulse's ::after turns with its parent and grows as a diamond.
|
|
26
|
+
// A clip-path would cut that border into four corner slivers and would need a second
|
|
27
|
+
// element to draw the ring, which this empty <span> does not have.
|
|
28
|
+
// A transform does not change layout, so the smaller square alone would leave a row
|
|
29
|
+
// short of the dot's size: the margin gives the layout box the difference back, half on
|
|
30
|
+
// each side, so a label beside the diamond sits where it sits beside the dot.
|
|
31
|
+
&_shape-diamond {
|
|
32
|
+
@side: round((@statusDotSizeMd / @statusDotDiamondRatio), @statusDotDiamondPrecision);
|
|
33
|
+
width: @side;
|
|
34
|
+
height: @side;
|
|
35
|
+
margin: round(((@statusDotSizeMd - @side) / 2), @statusDotDiamondPrecision);
|
|
36
|
+
border-radius: @statusDotDiamondRadius;
|
|
37
|
+
transform: rotate(@statusDotDiamondRotation);
|
|
38
|
+
}
|
|
39
|
+
&_shape-diamond&_size-sm {
|
|
40
|
+
@side: round((@statusDotSizeSm / @statusDotDiamondRatio), @statusDotDiamondPrecision);
|
|
41
|
+
width: @side;
|
|
42
|
+
height: @side;
|
|
43
|
+
margin: round(((@statusDotSizeSm - @side) / 2), @statusDotDiamondPrecision);
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
&_status-active {
|
|
22
47
|
--smwb-status-dot-color: var(--smui-infoColor);
|
|
23
48
|
}
|
|
@@ -29,24 +29,77 @@
|
|
|
29
29
|
box-shadow: inset 0 @tabGroupsActiveLineWidth 0 0 var(--smui-primaryColor);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// From a basis of 0 the tabs take only what the header has left: they give way and scroll first,
|
|
33
|
+
// and the strip content shrinks only once they are gone.
|
|
32
34
|
&__tabs {
|
|
33
|
-
flex: 1 1
|
|
35
|
+
flex: 1 1 0;
|
|
34
36
|
min-width: 0;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
//
|
|
39
|
+
// What the app puts at the end of the tab row (`stripActions`). It keeps its size while the tabs
|
|
40
|
+
// can give way, then is clipped at its end, so the group's actions button never leaves the row.
|
|
41
|
+
&__strip-actions {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
flex: 0 1 auto;
|
|
45
|
+
min-width: 0;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
gap: @tabGroupsStripActionsGap;
|
|
48
|
+
padding: 0 @tabGroupsStripActionsPaddingX;
|
|
49
|
+
|
|
50
|
+
// A component that renders nothing leaves the wrapper empty (React cannot tell it from
|
|
51
|
+
// outside): no padding, no box.
|
|
52
|
+
&:empty {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Centred on the row whatever `align-self` a control carries: `Button` sets `flex-start`, so that
|
|
58
|
+
// it does not stretch in a column, and would sit on the row's top edge. Through the header, to
|
|
59
|
+
// outrank that rule whichever stylesheet comes first.
|
|
60
|
+
&__header &__strip-actions > * {
|
|
61
|
+
align-self: center;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The group's actions button is an icon-only control: it carries the `smwb-button_icon-only` marker
|
|
65
|
+
// that `Button` writes for `iconOnly`, and its box is a square of the row's control height - the
|
|
66
|
+
// height the tabs beside it are. The side is a component variable, not Tabs' fixed 40px trigger
|
|
67
|
+
// width: that width, stretched over a dense row, drew a 40x36 rectangle where the mockups draw a
|
|
68
|
+
// square. A dense row is `@tabDenseHeight`, off the `--smui-control-h-*` grid, and marks itself.
|
|
69
|
+
// `min-width` and the horizontal padding are gone with it, so the icon sits in the middle.
|
|
38
70
|
&__actions-trigger {
|
|
71
|
+
--smwb-tab-groups-actions-size: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
72
|
+
|
|
39
73
|
display: inline-flex;
|
|
40
74
|
align-items: center;
|
|
41
75
|
justify-content: center;
|
|
76
|
+
box-sizing: border-box;
|
|
42
77
|
flex: 0 0 auto;
|
|
43
|
-
|
|
78
|
+
// Its own height is the square now, not the row's stretch, so a row that grows past it (a tab
|
|
79
|
+
// with a two-line label) still keeps the button in the middle of the row.
|
|
80
|
+
align-self: center;
|
|
81
|
+
min-width: 0;
|
|
82
|
+
width: var(--smwb-tab-groups-actions-size);
|
|
83
|
+
height: var(--smwb-tab-groups-actions-size);
|
|
44
84
|
padding: 0;
|
|
45
85
|
border: none;
|
|
46
86
|
background: none;
|
|
47
87
|
color: var(--smui-onSurfaceVariant);
|
|
48
88
|
cursor: pointer;
|
|
49
89
|
|
|
90
|
+
// Compact tab rows (`TabGroups` `dense`): the square follows the shorter row.
|
|
91
|
+
&--dense {
|
|
92
|
+
--smwb-tab-groups-actions-size: var(--smui-tabDenseHeight, @tabDenseHeight);
|
|
93
|
+
|
|
94
|
+
// The tabs beside it are the sm step (44px) at least on a coarse pointer, so it is too.
|
|
95
|
+
@media (pointer: coarse) {
|
|
96
|
+
--smwb-tab-groups-actions-size: max(
|
|
97
|
+
var(--smui-tabDenseHeight, @tabDenseHeight),
|
|
98
|
+
var(--smui-control-h-sm, @smui-control-h-sm-coarse)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
50
103
|
&:hover:not(:disabled) {
|
|
51
104
|
background-color: var(--smui-onSurfaceHover);
|
|
52
105
|
}
|