@smwb/ui-styles 2.1.0 → 2.2.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/dagView/dagView.less +34 -1
- 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 +28 -1
- package/less/components/tabs/tab/tab.less +41 -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/variables.less +2 -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;
|
|
@@ -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);
|
|
@@ -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,11 +29,38 @@
|
|
|
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
|
|
|
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
|
+
|
|
37
64
|
// The group's actions button: the box of Tabs' overflow trigger, which it sits beside.
|
|
38
65
|
&__actions-trigger {
|
|
39
66
|
display: inline-flex;
|
|
@@ -213,6 +213,47 @@
|
|
|
213
213
|
text-transform: none;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
// Content-width tabs (Tabs `fit`): a tab is as wide as what it holds — marker, label, close button —
|
|
217
|
+
// and the row no longer shares itself out between its tabs, so what is left of the row stays empty.
|
|
218
|
+
// The width stays between two tokens: a short label does not shrink the tab to a sliver, a long one
|
|
219
|
+
// is cut with an ellipsis at the maximum (the full text is the tab's `title`). The limits belong to
|
|
220
|
+
// the row's flex child: the item when the tab has a close button or actions, the tab otherwise. In
|
|
221
|
+
// an item the tab gives way to its controls, which keep their size, and fills the minimum.
|
|
222
|
+
.smwb-tabs--fit {
|
|
223
|
+
// How far a cut label's box reaches past its line box, so that overflow: hidden, which text-overflow
|
|
224
|
+
// needs, does not clip the descenders and accents that line-height: 1 leaves outside it.
|
|
225
|
+
@tabFitLabelOverhang: 0.25em;
|
|
226
|
+
|
|
227
|
+
.smwb-tab,
|
|
228
|
+
.smwb-tab-item {
|
|
229
|
+
flex: 0 0 auto;
|
|
230
|
+
min-width: var(--smui-tabFitMinWidth, @tabFitMinWidth);
|
|
231
|
+
max-width: var(--smui-tabFitMaxWidth, @tabFitMaxWidth);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.smwb-tab-item > .smwb-tab {
|
|
235
|
+
flex: 1 1 auto;
|
|
236
|
+
min-width: 0;
|
|
237
|
+
max-width: none;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.smwb-tab__content {
|
|
241
|
+
min-width: 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.smwb-tab__icon {
|
|
245
|
+
flex: 0 0 auto;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.smwb-tab__text-label {
|
|
249
|
+
min-width: 0;
|
|
250
|
+
padding-block: @tabFitLabelOverhang;
|
|
251
|
+
margin-block: -@tabFitLabelOverhang;
|
|
252
|
+
overflow: hidden;
|
|
253
|
+
text-overflow: ellipsis;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
216
257
|
// The close button shows when it is reachable: the item is hovered (item not disabled),
|
|
217
258
|
// the item is the active tab, or focus is inside the item. The disabled button stays
|
|
218
259
|
// hidden; the reveal restores what the hidden defaults below took away. Hidden means
|
|
@@ -41,6 +41,30 @@
|
|
|
41
41
|
min-height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
42
42
|
justify-content: center;
|
|
43
43
|
}
|
|
44
|
+
// The compact look, for a status row or a toolbar: the label shares the line with
|
|
45
|
+
// the switch (placement "top", the default, counts as "left"; "right" keeps its
|
|
46
|
+
// order) and the row is the small control height, capped at the compact maximum, in
|
|
47
|
+
// place of the size rule's. The :has() rules above weigh the same, so this one
|
|
48
|
+
// follows them. The switch gives up height to fit the row; its width and thumb
|
|
49
|
+
// stay, and the thumb centres itself on the track. Nothing here clips: the focus
|
|
50
|
+
// ring and the thumb halo draw outside the row.
|
|
51
|
+
@compact-height: min(var(--smui-control-h-sm, @smui-control-h-sm), @toggleCompactMaxHeight);
|
|
52
|
+
&__wrapper_compact:has(.smwb-toggle) {
|
|
53
|
+
flex-direction: row;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: flex-start;
|
|
56
|
+
min-height: @compact-height;
|
|
57
|
+
height: @compact-height;
|
|
58
|
+
.smwb-toggle {
|
|
59
|
+
height: min(@toggleTrackHeight, 100%);
|
|
60
|
+
}
|
|
61
|
+
.smwb-toggle__label {
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
&__wrapper_compact.smwb-toggle__wrapper_label-right:has(.smwb-toggle) {
|
|
66
|
+
flex-direction: row-reverse;
|
|
67
|
+
}
|
|
44
68
|
&.smwb-disabled {
|
|
45
69
|
opacity: 0.35;
|
|
46
70
|
pointer-events: none;
|
|
@@ -1,31 +1,54 @@
|
|
|
1
1
|
.smwb-tree {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
// The row height, the node's left padding and the corner's horizontal arm are custom properties of the tree,
|
|
3
|
+
// so the guide corner (drawn by each node's ::before) follows the row: it is half the row height deep, which
|
|
4
|
+
// puts its arm at the middle of a row of any height. The dense look swaps in the small control height and a
|
|
5
|
+
// tighter indent; a caller can set any of the three on the tree itself (the `style` prop).
|
|
6
|
+
--smwb-tree-row-h: var(--smui-control-h-md, @smui-control-h-md);
|
|
7
|
+
--smwb-tree-indent: @treeViewIndent;
|
|
8
|
+
--smwb-tree-arm: @treeViewGuideArm;
|
|
9
|
+
|
|
10
|
+
&_dense {
|
|
11
|
+
--smwb-tree-row-h: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
12
|
+
--smwb-tree-indent: @treeViewIndentDense;
|
|
13
|
+
--smwb-tree-arm: @treeViewGuideArmDense;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// A root node sits alone in its wrapper, so it is the wrapper's first child: that is the one to leave without
|
|
17
|
+
// a connector. Matched through the child combinator, the rule does not reach the first child of a nested level.
|
|
18
|
+
&__wrapper > .smwb-tree__node:first-child {
|
|
19
|
+
border-left: 0;
|
|
20
|
+
&::before {
|
|
21
|
+
opacity: 0;
|
|
10
22
|
}
|
|
11
23
|
}
|
|
24
|
+
|
|
25
|
+
// Without guides a nested node swaps its 1px line for the same width of padding, so the levels keep their step.
|
|
26
|
+
&_no-guides &__node &__node {
|
|
27
|
+
border-left-width: 0;
|
|
28
|
+
padding-left: calc(var(--smwb-tree-indent) + @treeViewGuideWidth);
|
|
29
|
+
|
|
30
|
+
&::before {
|
|
31
|
+
display: none;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
12
35
|
&__node {
|
|
13
36
|
&:last-child {
|
|
14
37
|
border-left-color: transparent;
|
|
15
38
|
}
|
|
16
|
-
padding-left:
|
|
17
|
-
margin-left:
|
|
39
|
+
padding-left: var(--smwb-tree-indent);
|
|
40
|
+
margin-left: @treeViewNodeMargin;
|
|
18
41
|
position: relative;
|
|
19
|
-
border-left:
|
|
42
|
+
border-left: @treeViewGuideWidth solid var(--smui-primaryColor);
|
|
20
43
|
|
|
21
44
|
&::before {
|
|
22
45
|
position: absolute;
|
|
23
46
|
top: 0;
|
|
24
|
-
left:
|
|
25
|
-
height:
|
|
26
|
-
width:
|
|
27
|
-
border-bottom:
|
|
28
|
-
border-left:
|
|
47
|
+
left: -@treeViewGuideWidth;
|
|
48
|
+
height: calc(var(--smwb-tree-row-h) / 2);
|
|
49
|
+
width: var(--smwb-tree-arm);
|
|
50
|
+
border-bottom: @treeViewGuideWidth solid var(--smui-primaryColor);
|
|
51
|
+
border-left: @treeViewGuideWidth solid var(--smui-primaryColor);
|
|
29
52
|
content: "";
|
|
30
53
|
font-weight: 600;
|
|
31
54
|
font-size: 14px;
|
|
@@ -54,7 +77,7 @@
|
|
|
54
77
|
gap: @treeViewItemGap;
|
|
55
78
|
// min-height, not height: a fixed row height let a wrapped two-line label
|
|
56
79
|
// overflow the node and overlap the next one.
|
|
57
|
-
min-height:
|
|
80
|
+
min-height: var(--smwb-tree-row-h);
|
|
58
81
|
}
|
|
59
82
|
|
|
60
83
|
&__toggle {
|
|
@@ -97,6 +97,14 @@
|
|
|
97
97
|
@avatarGroupMaxStacked: 12; // children laid each over the next; any past these overlap the other way
|
|
98
98
|
|
|
99
99
|
@breadcrumbsGap: @smui-space-sm;
|
|
100
|
+
// Single-line trail: the leading crumbs give way first (this many times as fast as the last one), down to
|
|
101
|
+
// a floor, so the last crumb is cut only once they are.
|
|
102
|
+
@breadcrumbsLeadingShrink: 100;
|
|
103
|
+
@breadcrumbsLeadingMinWidth: 3em;
|
|
104
|
+
// The last crumb never gets narrower than this, so a very narrow box still shows the start of the page title.
|
|
105
|
+
@breadcrumbsLastMinWidth: 4em;
|
|
106
|
+
// How far a clipped crumb still paints outside its box: a 2px focus ring at a 2px offset.
|
|
107
|
+
@breadcrumbsClipMargin: @smui-space-xs;
|
|
100
108
|
|
|
101
109
|
@dividerSpacing: @smui-space-sm;
|
|
102
110
|
@dividerTextGap: @smui-space-md;
|
|
@@ -120,6 +128,8 @@
|
|
|
120
128
|
@appBarPaddingX: @smui-space-lg;
|
|
121
129
|
@appBarActionPadding: @smui-space-md;
|
|
122
130
|
@appBarActionsGap: 10px; // off-grid
|
|
131
|
+
// How far a clipped title still paints outside its box: a 2px focus ring at a 2px offset.
|
|
132
|
+
@appBarClipMargin: @smui-space-xs;
|
|
123
133
|
// Width reserved for the OS window buttons in `AppBar variant="window"`: the macOS traffic lights of Electron's
|
|
124
134
|
// `hiddenInset` end around 70-78px, so with @appBarPaddingX the content starts at 80px; Windows/Linux draw three
|
|
125
135
|
// 46px caption buttons. Not theme tokens — an app overrides both sides with --smui-appBarWindowControlsWidth.
|
|
@@ -177,9 +187,18 @@
|
|
|
177
187
|
@progressDotMargin: @smui-space-xs;
|
|
178
188
|
@meterHeight: 6px;
|
|
179
189
|
@meterMinBarWidth: 3.5rem; // the bar keeps at least this much beside its text
|
|
190
|
+
@meterCompactHeight: 4px; // off-grid
|
|
191
|
+
@meterCompactBarWidth: 64px; // the compact meter's bar is this wide, not flexible
|
|
180
192
|
@statusDotSizeSm: 8px; // @smui-space-2
|
|
181
193
|
@statusDotSizeMd: 12px; // @smui-space-3
|
|
182
194
|
@statusDotRing: 2px; // the unknown status is a ring this thick
|
|
195
|
+
// A square turned 45deg spans side * sqrt(2), so the diamond's side is the dot's size
|
|
196
|
+
// divided by this: the two shapes then share one bounding box, and a margin makes up
|
|
197
|
+
// the layout box, which a transform leaves at the unturned side.
|
|
198
|
+
@statusDotDiamondRatio: sqrt(2);
|
|
199
|
+
@statusDotDiamondPrecision: 4; // decimals kept in the diamond's side and margin
|
|
200
|
+
@statusDotDiamondRotation: 45deg; // corner-up, the diamond of the onreel thread marker
|
|
201
|
+
@statusDotDiamondRadius: @smui-radius-none; // sharp corners; the dot's are a circle
|
|
183
202
|
|
|
184
203
|
// A QR code is always dark modules on a white square — never theme tokens, so no
|
|
185
204
|
// theme (or forced-colours mode, see the component's print/forced-color-adjust) can
|
|
@@ -261,6 +280,8 @@
|
|
|
261
280
|
@tabLabelPaddingLeft: @smui-space-sm;
|
|
262
281
|
@tabDensePaddingX: @smui-space-md;
|
|
263
282
|
@tabDenseHeight: 36px; // off-grid; the row height of Tabs dense, the height of the compact onreel strips
|
|
283
|
+
@tabFitMinWidth: (@smui-space-10 * 2); // Tabs `fit`: a short label does not shrink the tab below this
|
|
284
|
+
@tabFitMaxWidth: (@smui-space-16 * 4); // Tabs `fit`: a longer label is cut with an ellipsis at this width
|
|
264
285
|
@tabCloseSize: @smui-space-6; // the close button of a closable tab
|
|
265
286
|
@tabControlsGap: @smui-space-xs; // between a tab's close button, its actions and the row's next tab
|
|
266
287
|
@tabsFadeWidth: 2.5rem; // scrollable row: the fading edge beyond which tabs are hidden
|
|
@@ -273,6 +294,8 @@
|
|
|
273
294
|
@tabGroupsSeparatorHitArea: 8px; // off-grid; the invisible grip around that track
|
|
274
295
|
@tabGroupsDropTintOpacity: 0.16; // how much primary the zone a dragged tab would land in shows
|
|
275
296
|
@tabGroupsActiveLineWidth: 2px; // off-grid; the line over the header of the group in use
|
|
297
|
+
@tabGroupsStripActionsGap: @smui-space-xs; // between the controls the app puts at the end of a group's tab row
|
|
298
|
+
@tabGroupsStripActionsPaddingX: @smui-space-xs; // that content's distance from the tabs and from the group's actions button
|
|
276
299
|
|
|
277
300
|
@tableCellPaddingX: @smui-space-lg;
|
|
278
301
|
@tableToolbarMarginBottom: 10px; // off-grid
|
|
@@ -295,11 +318,20 @@
|
|
|
295
318
|
@textFieldAdornmentFilledMarginTop: @smui-space-md;
|
|
296
319
|
|
|
297
320
|
@toggleGap: @smui-space-sm;
|
|
321
|
+
// The compact Toggle's row is the small control height, but never taller than this.
|
|
322
|
+
@toggleCompactMaxHeight: 28px;
|
|
298
323
|
|
|
299
324
|
@tooltipPaddingX: @smui-space-sm;
|
|
300
325
|
|
|
301
326
|
@treeViewIndent: 30px; // off-grid
|
|
302
327
|
@treeViewItemGap: 10px; // off-grid
|
|
328
|
+
@treeViewGuideWidth: 1px;
|
|
329
|
+
@treeViewNodeMargin: 9px; // off-grid
|
|
330
|
+
@treeViewGuideArm: 25px; // off-grid
|
|
331
|
+
// The dense look. A node's indent is its padding; with @treeViewNodeMargin (9px) and @treeViewGuideWidth (1px) the step from a row to its
|
|
332
|
+
// children's is 16px (6 + 9 + 1), the arm ends at the child's row, and the row height is @smui-control-h-sm.
|
|
333
|
+
@treeViewIndentDense: 6px; // off-grid
|
|
334
|
+
@treeViewGuideArmDense: 6px; // off-grid
|
|
303
335
|
|
|
304
336
|
/*-------------------
|
|
305
337
|
Text Field
|
|
@@ -367,6 +399,9 @@
|
|
|
367
399
|
Button
|
|
368
400
|
--------------------*/
|
|
369
401
|
@buttonBorderRadius: 24px;
|
|
402
|
+
// The most an icon-only button rounds its corners: the smaller of this and @buttonBorderRadius.
|
|
403
|
+
// A pill radius would make the square a circle; set @smui-radius-pill here to get one.
|
|
404
|
+
@buttonIconOnlyMaxBorderRadius: @smui-radius-md;
|
|
370
405
|
@smallButtonFontSize: 13px;
|
|
371
406
|
@mediumButtonFontSize: 14px;
|
|
372
407
|
@largeButtonFontSize: 15px;
|
|
@@ -529,6 +564,7 @@
|
|
|
529
564
|
// are the theme's runtime tokens, so the dark theme follows on its own.
|
|
530
565
|
@dagViewNodeBg: ~"var(--smui-surfaceBackground)";
|
|
531
566
|
@dagViewNodeBorder: ~"var(--smui-outlineColor)";
|
|
567
|
+
@dagViewNodeBorderStyle: solid;
|
|
532
568
|
@dagViewEdgeColor: ~"var(--smui-outlineColor)";
|
|
533
569
|
@dagViewEdgeActiveColor: ~"var(--smui-primaryColor)";
|
|
534
570
|
@dagViewSelectedRing: ~"var(--smui-primaryColor)";
|
|
@@ -540,6 +576,13 @@
|
|
|
540
576
|
@dagViewStatusWarning: ~"var(--smui-warningColor)";
|
|
541
577
|
@dagViewStatusError: ~"var(--smui-errorColor)";
|
|
542
578
|
@dagViewStatusSkipped: ~"var(--smui-disabledTextColor)";
|
|
579
|
+
// The line style of a status's node frame; `false`: the theme-wide @dagViewNodeBorderStyle.
|
|
580
|
+
@dagViewStatusPendingBorderStyle: false;
|
|
581
|
+
@dagViewStatusRunningBorderStyle: false;
|
|
582
|
+
@dagViewStatusSuccessBorderStyle: false;
|
|
583
|
+
@dagViewStatusWarningBorderStyle: false;
|
|
584
|
+
@dagViewStatusErrorBorderStyle: false;
|
|
585
|
+
@dagViewStatusSkippedBorderStyle: false;
|
|
543
586
|
// How far the nodes and edges away from the selection fade, with dimUnrelated.
|
|
544
587
|
@dagViewDimOpacity: 0.35;
|
|
545
588
|
// The graph's height when the app sets none (its `height` prop or `style`).
|
package/less/variables.less
CHANGED
|
@@ -93,6 +93,8 @@
|
|
|
93
93
|
--smui-tabIconColor: @tabIconColor;
|
|
94
94
|
--smui-tabColorDefault: @tabColorDefault;
|
|
95
95
|
--smui-tabDenseHeight: @tabDenseHeight;
|
|
96
|
+
--smui-tabFitMinWidth: @tabFitMinWidth;
|
|
97
|
+
--smui-tabFitMaxWidth: @tabFitMaxWidth;
|
|
96
98
|
|
|
97
99
|
--smui-sliderColor: @sliderColor;
|
|
98
100
|
--smui-sliderDisabledColor: @sliderDisabledColor;
|
package/normalize.css
CHANGED
|
@@ -25,12 +25,11 @@ main {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Correct the
|
|
29
|
-
*
|
|
28
|
+
* Correct the margin on `h1` elements. The font size is set with the other
|
|
29
|
+
* heading sizes at the end of this file, behind `:where()`.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
h1 {
|
|
33
|
-
font-size: 2em;
|
|
34
33
|
margin: 0.67em 0;
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -74,7 +73,7 @@ a {
|
|
|
74
73
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
|
75
74
|
*/
|
|
76
75
|
|
|
77
|
-
abbr[title] {
|
|
76
|
+
:where(abbr[title]) {
|
|
78
77
|
border-bottom: none; /* 1 */
|
|
79
78
|
text-decoration: underline; /* 2 */
|
|
80
79
|
text-decoration: underline dotted; /* 2 */
|
|
@@ -186,10 +185,7 @@ select {
|
|
|
186
185
|
* Correct the inability to style clickable types in iOS and Safari.
|
|
187
186
|
*/
|
|
188
187
|
|
|
189
|
-
button,
|
|
190
|
-
[type="button"],
|
|
191
|
-
[type="reset"],
|
|
192
|
-
[type="submit"] {
|
|
188
|
+
:where(button, [type="button"], [type="reset"], [type="submit"]) {
|
|
193
189
|
-webkit-appearance: button;
|
|
194
190
|
}
|
|
195
191
|
|
|
@@ -197,25 +193,11 @@ button,
|
|
|
197
193
|
* Remove the inner border and padding in Firefox.
|
|
198
194
|
*/
|
|
199
195
|
|
|
200
|
-
button::-moz-focus-inner
|
|
201
|
-
[type="button"]::-moz-focus-inner,
|
|
202
|
-
[type="reset"]::-moz-focus-inner,
|
|
203
|
-
[type="submit"]::-moz-focus-inner {
|
|
196
|
+
:where(button, [type="button"], [type="reset"], [type="submit"])::-moz-focus-inner {
|
|
204
197
|
border-style: none;
|
|
205
198
|
padding: 0;
|
|
206
199
|
}
|
|
207
200
|
|
|
208
|
-
/**
|
|
209
|
-
* Restore the focus styles unset by the previous rule.
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
button:-moz-focusring,
|
|
213
|
-
[type="button"]:-moz-focusring,
|
|
214
|
-
[type="reset"]:-moz-focusring,
|
|
215
|
-
[type="submit"]:-moz-focusring {
|
|
216
|
-
outline: 1px dotted ButtonText;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
201
|
/**
|
|
220
202
|
* Correct the padding in Firefox.
|
|
221
203
|
*/
|
|
@@ -261,8 +243,7 @@ textarea {
|
|
|
261
243
|
* 2. Remove the padding in IE 10.
|
|
262
244
|
*/
|
|
263
245
|
|
|
264
|
-
[type="checkbox"],
|
|
265
|
-
[type="radio"] {
|
|
246
|
+
:where([type="checkbox"], [type="radio"]) {
|
|
266
247
|
box-sizing: border-box; /* 1 */
|
|
267
248
|
padding: 0; /* 2 */
|
|
268
249
|
}
|
|
@@ -271,8 +252,8 @@ textarea {
|
|
|
271
252
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
|
272
253
|
*/
|
|
273
254
|
|
|
274
|
-
[type="number"]::-webkit-inner-spin-button,
|
|
275
|
-
[type="number"]::-webkit-outer-spin-button {
|
|
255
|
+
:where([type="number"])::-webkit-inner-spin-button,
|
|
256
|
+
:where([type="number"])::-webkit-outer-spin-button {
|
|
276
257
|
height: auto;
|
|
277
258
|
}
|
|
278
259
|
|
|
@@ -281,7 +262,7 @@ textarea {
|
|
|
281
262
|
* 2. Correct the outline style in Safari.
|
|
282
263
|
*/
|
|
283
264
|
|
|
284
|
-
[type="search"] {
|
|
265
|
+
:where([type="search"]) {
|
|
285
266
|
-webkit-appearance: textfield; /* 1 */
|
|
286
267
|
outline-offset: -2px; /* 2 */
|
|
287
268
|
}
|
|
@@ -290,7 +271,7 @@ textarea {
|
|
|
290
271
|
* Remove the inner padding in Chrome and Safari on macOS.
|
|
291
272
|
*/
|
|
292
273
|
|
|
293
|
-
[type="search"]::-webkit-search-decoration {
|
|
274
|
+
:where([type="search"])::-webkit-search-decoration {
|
|
294
275
|
-webkit-appearance: none;
|
|
295
276
|
}
|
|
296
277
|
|
|
@@ -353,13 +334,20 @@ template {
|
|
|
353
334
|
-webkit-box-sizing: border-box;
|
|
354
335
|
box-sizing: border-box;
|
|
355
336
|
}
|
|
356
|
-
:focus,
|
|
357
|
-
:active {
|
|
337
|
+
:where(:focus, :active) {
|
|
358
338
|
outline: none;
|
|
359
339
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
340
|
+
/**
|
|
341
|
+
* Restore the focus styles unset by the rule above. Declared after it: both have zero
|
|
342
|
+
* specificity, so the later one wins, and a component's own :focus-visible ring beats both.
|
|
343
|
+
*/
|
|
344
|
+
:where(
|
|
345
|
+
button:-moz-focusring,
|
|
346
|
+
[type="button"]:-moz-focusring,
|
|
347
|
+
[type="reset"]:-moz-focusring,
|
|
348
|
+
[type="submit"]:-moz-focusring
|
|
349
|
+
) {
|
|
350
|
+
outline: 1px dotted ButtonText;
|
|
363
351
|
}
|
|
364
352
|
nav,
|
|
365
353
|
footer,
|
|
@@ -392,11 +380,7 @@ button::-moz-focus-inner {
|
|
|
392
380
|
padding: 0;
|
|
393
381
|
border: 0;
|
|
394
382
|
}
|
|
395
|
-
a
|
|
396
|
-
a:visited {
|
|
397
|
-
text-decoration: none;
|
|
398
|
-
}
|
|
399
|
-
a:hover {
|
|
383
|
+
a {
|
|
400
384
|
text-decoration: none;
|
|
401
385
|
}
|
|
402
386
|
ul li {
|
|
@@ -406,72 +390,78 @@ img {
|
|
|
406
390
|
vertical-align: top;
|
|
407
391
|
}
|
|
408
392
|
|
|
409
|
-
/*
|
|
410
|
-
|
|
393
|
+
/*
|
|
394
|
+
* heading elements
|
|
395
|
+
*
|
|
396
|
+
* All behind :where(), so these have zero specificity and any component class (the
|
|
397
|
+
* font size and weight of Typography, say) wins, in or out of article, aside, nav and
|
|
398
|
+
* section. Among themselves they cascade in source order, as before.
|
|
399
|
+
*
|
|
400
|
+
* The section rules keep `:-webkit-any()`, which Firefox does not know: :where() takes a
|
|
401
|
+
* forgiving list, so there the branch matches nothing and a bare h1 stays 2em, as it
|
|
402
|
+
* always did. Do not turn it into :is(), that would resize Firefox's headings.
|
|
403
|
+
*/
|
|
404
|
+
:where(h1, h2, h3, h4, h5, h6) {
|
|
411
405
|
display: block;
|
|
412
|
-
font-size: 2em;
|
|
413
406
|
font-weight: bold;
|
|
414
407
|
}
|
|
415
408
|
|
|
416
|
-
|
|
409
|
+
:where(h1) {
|
|
410
|
+
font-size: 2em;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
:where(:-webkit-any(article, aside, nav, section) h1) {
|
|
417
414
|
font-size: 1.5em;
|
|
418
415
|
}
|
|
419
416
|
|
|
420
|
-
:-webkit-any(article, aside, nav, section) :-webkit-any(article, aside, nav, section) h1 {
|
|
417
|
+
:where(:-webkit-any(article, aside, nav, section) :-webkit-any(article, aside, nav, section) h1) {
|
|
421
418
|
font-size: 1.17em;
|
|
422
419
|
}
|
|
423
420
|
|
|
424
|
-
|
|
425
|
-
:-webkit-any(article, aside, nav, section)
|
|
421
|
+
:where(
|
|
426
422
|
:-webkit-any(article, aside, nav, section)
|
|
427
|
-
|
|
423
|
+
:-webkit-any(article, aside, nav, section)
|
|
424
|
+
:-webkit-any(article, aside, nav, section)
|
|
425
|
+
h1
|
|
426
|
+
) {
|
|
428
427
|
font-size: 1em;
|
|
429
428
|
}
|
|
430
429
|
|
|
431
|
-
|
|
432
|
-
:-webkit-any(article, aside, nav, section)
|
|
433
|
-
:-webkit-any(article, aside, nav, section)
|
|
430
|
+
:where(
|
|
434
431
|
:-webkit-any(article, aside, nav, section)
|
|
435
|
-
|
|
432
|
+
:-webkit-any(article, aside, nav, section)
|
|
433
|
+
:-webkit-any(article, aside, nav, section)
|
|
434
|
+
:-webkit-any(article, aside, nav, section)
|
|
435
|
+
h1
|
|
436
|
+
) {
|
|
436
437
|
font-size: 0.83em;
|
|
437
438
|
}
|
|
438
439
|
|
|
439
|
-
|
|
440
|
+
:where(
|
|
440
441
|
:-webkit-any(article, aside, nav, section)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
:-webkit-any(article, aside, nav, section)
|
|
443
|
+
:-webkit-any(article, aside, nav, section)
|
|
444
|
+
:-webkit-any(article, aside, nav, section)
|
|
445
|
+
:-webkit-any(article, aside, nav, section)
|
|
446
|
+
h1
|
|
447
|
+
) {
|
|
445
448
|
font-size: 0.67em;
|
|
446
449
|
}
|
|
447
450
|
|
|
448
|
-
h2 {
|
|
449
|
-
display: block;
|
|
451
|
+
:where(h2) {
|
|
450
452
|
font-size: 1.5em;
|
|
451
|
-
font-weight: bold;
|
|
452
453
|
}
|
|
453
454
|
|
|
454
|
-
h3 {
|
|
455
|
-
display: block;
|
|
455
|
+
:where(h3) {
|
|
456
456
|
font-size: 1.17em;
|
|
457
|
-
font-weight: bold;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
h4 {
|
|
461
|
-
display: block;
|
|
462
|
-
font-weight: bold;
|
|
463
457
|
}
|
|
464
458
|
|
|
465
|
-
h5 {
|
|
466
|
-
display: block;
|
|
459
|
+
:where(h5) {
|
|
467
460
|
font-size: 0.83em;
|
|
468
|
-
font-weight: bold;
|
|
469
461
|
}
|
|
470
462
|
|
|
471
|
-
h6 {
|
|
472
|
-
display: block;
|
|
463
|
+
:where(h6) {
|
|
473
464
|
font-size: 0.67em;
|
|
474
|
-
font-weight: bold;
|
|
475
465
|
}
|
|
476
466
|
|
|
477
467
|
body {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smwb/ui-styles",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Framework-agnostic LESS design tokens and component styles (smwb-*) shared by the @smwb UI libraries. Prebuilt aggregate CSS lives in @smwb/ui-css.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"sideEffects": [
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"./package.json": "./package.json"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"lint": "node scripts/check-aggregate.mjs && node scripts/check-tokens.mjs && node scripts/check-control-heights.mjs && node scripts/check-typography-case.mjs && node scripts/check-chart-series.mjs"
|
|
22
|
+
"lint": "node scripts/check-aggregate.mjs && node scripts/check-tokens.mjs && node scripts/check-control-heights.mjs && node scripts/check-typography-case.mjs && node scripts/check-chart-series.mjs && node scripts/check-normalize-specificity.mjs"
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://sourcecraft.dev/elfenmail/ui",
|
|
25
25
|
"repository": {
|