@smwb/ui-styles 1.6.0 → 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 +157 -22
- package/less/components/appBar/appBar.less +108 -0
- package/less/components/button/button.less +7 -1
- package/less/components/checkbox/checkbox.less +37 -3
- package/less/components/chip/chip.less +15 -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/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/qrCode/qrCode.entry.less +2 -0
- package/less/components/qrCode/qrCode.less +35 -0
- package/less/components/radioButton/radioButton.less +32 -0
- package/less/components/selectField/selectField.less +21 -4
- 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/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/toggle/toggle.less +28 -1
- package/less/components/treeView/treeView.less +40 -2
- package/less/components.less +9 -0
- package/less/default/globals/default.variables.less +79 -0
- package/less/foundation/sizing.less +41 -5
- package/less/variables.less +5 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -19,18 +19,18 @@ npm install @smwb/ui-styles
|
|
|
19
19
|
|
|
20
20
|
## What's inside
|
|
21
21
|
|
|
22
|
-
| Path
|
|
23
|
-
|
|
|
24
|
-
| `less/components.less`
|
|
25
|
-
| `less/foundation/*`
|
|
26
|
-
| `less/default/globals/default.variables.less` | Semantic colors + per-component LESS variables
|
|
27
|
-
| `less/variables.less`
|
|
28
|
-
| `less/components/<name>/<name>.entry.less`
|
|
29
|
-
| `less/tokens.entry.less`
|
|
30
|
-
| `less/headless-base.less`
|
|
31
|
-
| `less/connects/rt/table.entry.less`
|
|
32
|
-
| `less/themes/*`
|
|
33
|
-
| `normalize.css`
|
|
22
|
+
| Path | Purpose |
|
|
23
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
24
|
+
| `less/components.less` | Aggregate entry — `@import`s foundation + every component |
|
|
25
|
+
| `less/foundation/*` | Tokens: palette, spacing, radius, elevation, breakpoints, sizing |
|
|
26
|
+
| `less/default/globals/default.variables.less` | Semantic colors + per-component LESS variables |
|
|
27
|
+
| `less/variables.less` | Declares the `--smui-*` tokens and emits them on `:root` (light) + `[data-theme="dark"]` |
|
|
28
|
+
| `less/components/<name>/<name>.entry.less` | Per-component entry (component rules only, no tokens) |
|
|
29
|
+
| `less/tokens.entry.less` | The `--smui-*` tokens at zero specificity (`:where(:root)`) for per-component CSS |
|
|
30
|
+
| `less/headless-base.less` | Foundation + theme variables only (no component rules) |
|
|
31
|
+
| `less/connects/rt/table.entry.less` | The React TanStack Table adapter's own rules (column resizer) |
|
|
32
|
+
| `less/themes/*` | Built-in theme packs (`summer`, `material`) |
|
|
33
|
+
| `normalize.css` | Optional CSS reset |
|
|
34
34
|
|
|
35
35
|
## Usage
|
|
36
36
|
|
|
@@ -93,21 +93,45 @@ is drawn for the 8th series). Light and dark are separate sets, so set both when
|
|
|
93
93
|
show in the dark theme. At runtime, set `--smwb-chart-series-N` on the chart itself (its `style`): the chart declares the
|
|
94
94
|
tokens on its own root, so a value set on `:root` or a wrapper does not reach it.
|
|
95
95
|
|
|
96
|
+
#### StatusDot colours
|
|
97
|
+
|
|
98
|
+
`StatusDot` reads only runtime tokens, so the dark theme follows without extra settings: `active` takes
|
|
99
|
+
`--smui-infoColor`, `attention` `--smui-warningColor`, `idle` `--smui-onSurfaceVariant`, `done`
|
|
100
|
+
`--smui-successColor`, `error` `--smui-errorColor` and `unknown` `--smui-outlineColor` (as a ring); `color` takes
|
|
101
|
+
the matching `--smui-*Color` token (`default` is `--smui-onSurfaceVariant`). Its sizes are `@statusDotSizeSm`
|
|
102
|
+
(8px), `@statusDotSizeMd` (12px) and `@statusDotRing` (2px, the ring of `unknown`) in `theme.config`.
|
|
103
|
+
|
|
104
|
+
Against `--smui-surfaceBackground` and `--smui-pageBackground`, the default theme's status colours measure
|
|
105
|
+
at least 3:1 in both modes (the lowest is `attention` on the light surface, 3.04:1). The semantic colours are one
|
|
106
|
+
value for both modes, so a theme that makes `@warningColor` lighter, or any of them darker for the dark theme,
|
|
107
|
+
changes the numbers: re-check them there. `color="secondary"` is the one name that falls short in the default dark
|
|
108
|
+
theme (2.65:1): use a status for state.
|
|
109
|
+
|
|
110
|
+
#### QrCode colours
|
|
111
|
+
|
|
112
|
+
`QrCode` never reads theme tokens for the code itself: the modules are always `@qrCodeDarkColor`
|
|
113
|
+
(`rgb(0 0 0)`) on `@qrCodeLightColor` (`rgb(255 255 255)`), including the quiet zone, so a phone camera
|
|
114
|
+
reads the code in the dark theme, under forced colours and in print (`forced-color-adjust: none` and
|
|
115
|
+
`print-color-adjust: exact` are set on the svg, and the same colours are written as SVG `fill` attributes,
|
|
116
|
+
so a copied or printed svg scans without the library CSS). Only the caption is themed
|
|
117
|
+
(`--smui-onSurfaceVariant`). The corner rounding is `@qrCodeRadius` (`@smui-radius-sm`); the svg clips to
|
|
118
|
+
it, and the quiet zone keeps the modules clear of the rounding.
|
|
119
|
+
|
|
96
120
|
#### DagView colours
|
|
97
121
|
|
|
98
|
-
The dependency graph (`DagView` in `@smwb/ui-solid`) takes its colours from theme variables that default to the
|
|
122
|
+
The dependency graph (`DagView` in `@smwb/ui-solid` and `@smwb/ui-react`) takes its colours from theme variables that default to the
|
|
99
123
|
runtime tokens, so the dark theme follows without extra settings:
|
|
100
124
|
|
|
101
|
-
| Variable (`theme.config`)
|
|
102
|
-
|
|
|
103
|
-
| `@dagViewNodeBg`
|
|
104
|
-
| `@dagViewNodeBorder`
|
|
105
|
-
| `@dagViewEdgeColor`
|
|
106
|
-
| `@dagViewEdgeActiveColor`
|
|
107
|
-
| `@dagViewSelectedRing`
|
|
125
|
+
| Variable (`theme.config`) | Runtime property on `.smwb-dag-view` | Default |
|
|
126
|
+
| ---------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------- |
|
|
127
|
+
| `@dagViewNodeBg` | `--smwb-dag-view-node-bg` | `var(--smui-surfaceBackground)` |
|
|
128
|
+
| `@dagViewNodeBorder` | `--smwb-dag-view-node-border` | `var(--smui-outlineColor)` |
|
|
129
|
+
| `@dagViewEdgeColor` | `--smwb-dag-view-edge-color` | `var(--smui-outlineColor)` |
|
|
130
|
+
| `@dagViewEdgeActiveColor` | `--smwb-dag-view-edge-active-color` | `var(--smui-primaryColor)` |
|
|
131
|
+
| `@dagViewSelectedRing` | `--smwb-dag-view-selected-ring` | `var(--smui-primaryColor)` |
|
|
108
132
|
| `@dagViewStatusIdle` … `@dagViewStatusSkipped` | `--smwb-dag-view-status-idle` … `-skipped` | outline, on-surface variant, info, success, warning, error, disabled text |
|
|
109
|
-
| `@dagViewDimOpacity`
|
|
110
|
-
| `@dagViewHeight`
|
|
133
|
+
| `@dagViewDimOpacity` | `--smwb-dag-view-dim-opacity` | `0.35` |
|
|
134
|
+
| `@dagViewHeight` | — (the graph's `height`) | `480px` |
|
|
111
135
|
|
|
112
136
|
The statuses are `idle`, `pending`, `running`, `success`, `warning`, `error` and `skipped`; a node with any other
|
|
113
137
|
status is drawn as `idle`. Each colour variable has a `…Dark` twin (e.g. `@dagViewStatusSuccessDark`), `false` by
|
|
@@ -120,6 +144,117 @@ node's accent comes from `--smwb-dag-view-accent`. For a status of your own, set
|
|
|
120
144
|
The graph's default height, `@dagViewHeight`, is set by the stylesheet, so its `height` prop or a height in its
|
|
121
145
|
`style` wins over it.
|
|
122
146
|
|
|
147
|
+
#### Swimlanes
|
|
148
|
+
|
|
149
|
+
`Swimlanes` (in `@smwb/ui-react` and `@smwb/ui-solid`) reads only runtime tokens, so the dark theme follows without
|
|
150
|
+
extra settings: the grid's surface and the sticky header's opaque background come from `--smui-surfaceBackground`,
|
|
151
|
+
the row divider from `--smui-dividerColor`, the hover tint from `--smui-onSurfaceHover`, the selected tint, the
|
|
152
|
+
selection stripe and the focus ring from `--smui-primaryColor`, and a disabled lane's text from
|
|
153
|
+
`--smui-disabledTextColor`.
|
|
154
|
+
|
|
155
|
+
| Variable (`theme.config`) | Runtime property on `.smwb-swimlanes` | Default |
|
|
156
|
+
| ------------------------- | ----------------------------------------------- | ------- |
|
|
157
|
+
| `@swimlanesHeaderWidth` | the fallback of `--smwb-swimlanes-header-width` | `240px` |
|
|
158
|
+
| `@swimlanesHeight` | — (the grid's `height`) | `480px` |
|
|
159
|
+
|
|
160
|
+
Three custom properties drive the layout and the component writes them on its own root:
|
|
161
|
+
`--smwb-swimlanes-row-height` (always, from `rowHeight`), `--smwb-swimlanes-header-width` (only with `headerWidth`)
|
|
162
|
+
and `--smwb-swimlanes-content-min-width` (only with `contentMinWidth`). The last two are yours to set, through the
|
|
163
|
+
props or at runtime on the grid itself (its `style`, which is merged last and wins). The row height is not: the
|
|
164
|
+
virtual window's maths needs it in JS, so it goes through `rowHeight` alone, and a different value in `style` would
|
|
165
|
+
resize the rows in CSS while the window still counts with `rowHeight`, leaving gaps or overlaps. A row's state is one
|
|
166
|
+
internal property, `--smwb-swimlanes-tint`, set on each row and read by both cells so the lane reads as one band:
|
|
167
|
+
`transparent`, `--smui-onSurfaceHover` on hover, and 12% of `--smui-primaryColor` when selected. It is declared on
|
|
168
|
+
the row, so a value set on the grid never reaches the cells.
|
|
169
|
+
|
|
170
|
+
`@swimlanesHeight` is set by the stylesheet, so the `height` prop or a height in `style` wins over it. A selected
|
|
171
|
+
lane also gets a 3px primary stripe on its header, so the selection is not shown by tint alone; forced colours draw
|
|
172
|
+
it as a `Highlight` outline on both cells instead. Cells clip, so content that needs more room needs a wider
|
|
173
|
+
`contentMinWidth`.
|
|
174
|
+
|
|
175
|
+
#### Composer
|
|
176
|
+
|
|
177
|
+
`Composer` is the task input: a textarea that grows from `minRows` to `maxRows`, an optional attach button, a
|
|
178
|
+
`toolbar` slot, a character counter and a send button that turns into Stop while the agent is busy. Its stylesheet is
|
|
179
|
+
`components/composer/composer.less` (per-component entry: `composer.entry.less`). The root's children are flat, and CSS
|
|
180
|
+
grid areas place them for each layout; the spacing is margins, so an absent child leaves no gap.
|
|
181
|
+
|
|
182
|
+
| Class | Element |
|
|
183
|
+
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
184
|
+
| `.smwb-composer` | the root; `_stacked` (field on top, a bar under it: attach, toolbar, counter, action) or `_inline` (one row: attach, field, counter, action; the toolbar, if any, under it) |
|
|
185
|
+
| `_focused`, `_disabled`, `_drag-active`, `_over-limit`, `_busy` | root states; `_focused` follows the textarea's focus, not `:focus-within` |
|
|
186
|
+
| `.smwb-composer__attachments`, `__toolbar` | slots above the field and in the bar |
|
|
187
|
+
| `.smwb-composer__field` | the textarea's wrapper; its `data-value` mirrors the text, and `--smwb-composer-min-rows` / `--smwb-composer-max-rows` set the height range |
|
|
188
|
+
| `.smwb-composer__input` | the textarea |
|
|
189
|
+
| `.smwb-composer__icon-button` | a round native button; with `__attach` and `__action` (`__action_stop` while busy) |
|
|
190
|
+
| `.smwb-composer__counter` (`_error`) | the `n / max` text |
|
|
191
|
+
| `.smwb-composer__status` | the visually hidden live region for the counter |
|
|
192
|
+
|
|
193
|
+
The textarea grows in CSS only: `.smwb-composer__field::after` repeats the text (`content: attr(data-value)`) in a
|
|
194
|
+
hidden box that shares the textarea's font, padding and line height, and the textarea fills the grid cell that box
|
|
195
|
+
sizes, up to `max-height`. Nothing is measured, so the height is right in server-rendered markup and follows a width
|
|
196
|
+
change. The send button is not natively disabled while it is unavailable: `aria-disabled="true"` mutes it, so it keeps
|
|
197
|
+
focus.
|
|
198
|
+
|
|
199
|
+
The colours are theme variables that default to the runtime tokens, so the dark theme follows without extra settings:
|
|
200
|
+
|
|
201
|
+
| Variable (`theme.config`) | Default |
|
|
202
|
+
| -------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
203
|
+
| `@composerBg`, `@composerBorder`, `@composerBorderFocus` | `var(--smui-surfaceBackground)`, `var(--smui-outlineColor)`, `var(--smui-primaryColor)` |
|
|
204
|
+
| `@composerText`, `@composerPlaceholder` | `var(--smui-onSurfaceColor)`, `var(--smui-onSurfaceVariant)` |
|
|
205
|
+
| `@composerCounter`, `@composerCounterError` | `var(--smui-onSurfaceVariant)`, `var(--smui-errorColor)` |
|
|
206
|
+
| `@composerActionBg`, `@composerActionColor` | `var(--smui-primaryColor)`, `var(--smui-onPrimaryColor)` |
|
|
207
|
+
| `@composerStopBg`, `@composerStopColor` | `var(--smui-onSurfaceColor)`, `var(--smui-surfaceBackground)` |
|
|
208
|
+
| `@composerDragBg` | `var(--smui-primaryContainer)` |
|
|
209
|
+
|
|
210
|
+
Sizes live in `composer.variables.less`: `@composerPadding`, `@composerGap`, `@composerRadius`, `@composerLineHeight`
|
|
211
|
+
(one text line, `1.5rem`), `@composerFieldPaddingY` / `@composerFieldPaddingX` and `@composerIconButtonSize`.
|
|
212
|
+
|
|
213
|
+
#### DiffStat colours
|
|
214
|
+
|
|
215
|
+
`DiffStat` draws its figures and cells in the theme's `--smui-successColor` and `--smui-errorColor`, each mixed toward
|
|
216
|
+
`--smui-onSurfaceColor` so that the text keeps 4.5:1 contrast (the raw tokens measure about 3.9–4.3:1) and a cell
|
|
217
|
+
keeps 3:1 against a neutral one, in the light and the dark theme alike. A cell nobody owns is an outline of the surface ink
|
|
218
|
+
(60% of it, 3.69:1 or better against the page and the surface in every bundled theme, light and dark), not a fill:
|
|
219
|
+
a fill light enough to sit quietly measured 1.08–1.29:1 against a light page and made "4 of 5" look like "5 of 5":
|
|
220
|
+
|
|
221
|
+
| Variable (`theme.config`) | Runtime property on `.smwb-diff-stat` | Default |
|
|
222
|
+
| ------------------------- | ------------------------------------- | --------------------------------------------------------------- |
|
|
223
|
+
| `@diffStatColorMix` | — (compiled into the two below) | `55%` of the success or error token |
|
|
224
|
+
| — | `--smwb-diff-stat-added` | success token mixed toward the surface ink |
|
|
225
|
+
| — | `--smwb-diff-stat-removed` | error token mixed toward the surface ink |
|
|
226
|
+
| `@diffStatNeutralMix` | `--smwb-diff-stat-neutral` | the surface ink at `60%`, the outline colour of an unowned cell |
|
|
227
|
+
|
|
228
|
+
Sizes are `@diffStatFontSize`, `@diffStatCompactFontSize`, `@diffStatCellWidth`, `@diffStatCellHeight`,
|
|
229
|
+
`@diffStatCompactCellHeight`, `@diffStatCellGap` and `@diffStatCellRadius`. At runtime, set the three properties on the
|
|
230
|
+
`DiffStat` itself (its `style`, or a class that outranks `.smwb-diff-stat`).
|
|
231
|
+
|
|
232
|
+
#### AppBar window controls
|
|
233
|
+
|
|
234
|
+
`AppBar variant="window"` is the title bar of a desktop app window (Electron, Tauri, an installed PWA with Window
|
|
235
|
+
Controls Overlay): the bar drags the window (`-webkit-app-region: drag`) and every control inside it is taken out of
|
|
236
|
+
the drag region. The width reserved for the OS window buttons is `@appBarWindowControlsLeft` (64px, the macOS traffic
|
|
237
|
+
lights) and `@appBarWindowControlsRight` (138px, three 46px Windows/Linux caption buttons). Both are read through one
|
|
238
|
+
runtime property, so an app retunes them without recompiling:
|
|
239
|
+
|
|
240
|
+
```css
|
|
241
|
+
.smwb-appbar.smwb-appbar_variant-window {
|
|
242
|
+
--smui-appBarWindowControlsWidth: 84px;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`--smui-appBarWindowControlsWidth` is deliberately **not** declared in `variables.less`: it is read with a fallback,
|
|
247
|
+
so unset means the Less defaults above. With `windowControls="auto"` the insets come from the shell instead —
|
|
248
|
+
`env(titlebar-area-x)` / `env(titlebar-area-width)` — and are 0 in a plain browser tab; `left`, `right` and `none`
|
|
249
|
+
pin them with a class. The insets are `padding-left` / `padding-right` on the bar, added to `@appBarPaddingX`, and
|
|
250
|
+
they survive `dense`. Overlays are `no-drag` globally — `[data-smwb-overlay-layer]`, `.smwb-menu`, `.smwb-tooltip`,
|
|
251
|
+
`.smwb-snackbars` and the library's own full-screen portals (`.smwb-chat-attachment-image__overlay`,
|
|
252
|
+
`.smwb-image-modal__overlay`, `.smwb-thumb-card__preview`, `.smwb-chat-shell`): Electron hit-tests drag regions by
|
|
253
|
+
geometry, and those popups portal to `<body>`. Inside the bar, the roles that keep `tabindex="-1"` while the group
|
|
254
|
+
holds the tab stop (`menuitemcheckbox`, `menuitemradio`, `treeitem`, `spinbutton`, `gridcell`, `listbox`,
|
|
255
|
+
`scrollbar`) are listed next to the focusable elements. A control the generic list cannot see opts out with
|
|
256
|
+
`.smwb-appbar__no-drag` or `data-no-drag`.
|
|
257
|
+
|
|
123
258
|
## License
|
|
124
259
|
|
|
125
260
|
[MIT](./LICENSE)
|
|
@@ -39,6 +39,90 @@
|
|
|
39
39
|
padding: @appBarActionPadding;
|
|
40
40
|
height: 48px;
|
|
41
41
|
}
|
|
42
|
+
// `variant="window"`: the bar is the title bar of a desktop app window (Electron, Tauri, an installed PWA
|
|
43
|
+
// with Window Controls Overlay). Compound and ordered after `&.smwb-dense` above, so its side insets
|
|
44
|
+
// out-rank the dense `padding` shorthand instead of being wiped by it.
|
|
45
|
+
&.smwb-appbar_variant-window {
|
|
46
|
+
-webkit-app-region: drag;
|
|
47
|
+
app-region: drag;
|
|
48
|
+
// Dragging the window out of the title must not select the title text.
|
|
49
|
+
user-select: none;
|
|
50
|
+
// Width to keep clear of the OS window buttons on each side. With no class at all (`windowControls="auto"`)
|
|
51
|
+
// the area comes from the shell: `env(titlebar-area-*)` is exact under Window Controls Overlay, and in a
|
|
52
|
+
// plain browser tab the fallbacks make both insets 0, so the bar looks like `variant="default"`.
|
|
53
|
+
--smwb-appbar-wc-left: env(titlebar-area-x, 0px);
|
|
54
|
+
--smwb-appbar-wc-right: calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw));
|
|
55
|
+
padding-left: calc(@appBarPaddingX + var(--smwb-appbar-wc-left));
|
|
56
|
+
padding-right: calc(@appBarPaddingX + var(--smwb-appbar-wc-right));
|
|
57
|
+
// `left`: the macOS traffic lights (`titleBarStyle: "hiddenInset"`), which Electron does not report
|
|
58
|
+
// through env() unless `titleBarOverlay` is on, hence the fixed width.
|
|
59
|
+
&.smwb-appbar_window-controls-left {
|
|
60
|
+
--smwb-appbar-wc-left: env(titlebar-area-x, var(--smui-appBarWindowControlsWidth, @appBarWindowControlsLeft));
|
|
61
|
+
}
|
|
62
|
+
// `right`: the caption buttons Windows/Linux draw at the right edge of the window. The fallback keeps
|
|
63
|
+
// their width clear by shortening the area the shell would have reported.
|
|
64
|
+
&.smwb-appbar_window-controls-right {
|
|
65
|
+
--smwb-appbar-wc-right: calc(
|
|
66
|
+
100vw - env(titlebar-area-x, 0px) -
|
|
67
|
+
env(titlebar-area-width, calc(100vw - var(--smui-appBarWindowControlsWidth, @appBarWindowControlsRight)))
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
&.smwb-appbar_window-controls-none {
|
|
71
|
+
--smwb-appbar-wc-left: 0px;
|
|
72
|
+
--smwb-appbar-wc-right: 0px;
|
|
73
|
+
}
|
|
74
|
+
// Electron delivers no mouse events at all inside a drag region, so every control in the bar has to opt
|
|
75
|
+
// out. Focusable and role-tagged elements are matched generically (the list is `:where()`, so an app's own
|
|
76
|
+
// selector still wins); a custom control that is neither takes `.smwb-appbar__no-drag` or `data-no-drag`.
|
|
77
|
+
:where(
|
|
78
|
+
a[href],
|
|
79
|
+
button,
|
|
80
|
+
input,
|
|
81
|
+
select,
|
|
82
|
+
textarea,
|
|
83
|
+
label,
|
|
84
|
+
summary,
|
|
85
|
+
iframe,
|
|
86
|
+
video[controls],
|
|
87
|
+
[contenteditable]:not([contenteditable="false"]),
|
|
88
|
+
[tabindex]:not([tabindex="-1"]),
|
|
89
|
+
[role="button"],
|
|
90
|
+
[role="link"],
|
|
91
|
+
[role="menuitem"],
|
|
92
|
+
[role="tab"],
|
|
93
|
+
[role="checkbox"],
|
|
94
|
+
[role="switch"],
|
|
95
|
+
[role="radio"],
|
|
96
|
+
[role="combobox"],
|
|
97
|
+
[role="textbox"],
|
|
98
|
+
[role="searchbox"],
|
|
99
|
+
[role="slider"],
|
|
100
|
+
[role="option"],
|
|
101
|
+
// Roving-tabindex widgets and the cells of composite widgets: while the group holds
|
|
102
|
+
// the tab stop their items carry `tabindex="-1"`, so `[tabindex]:not([tabindex="-1"])`
|
|
103
|
+
// above never matches them and only the role gets them out of the drag region.
|
|
104
|
+
[role="menuitemcheckbox"],
|
|
105
|
+
[role="menuitemradio"],
|
|
106
|
+
[role="treeitem"],
|
|
107
|
+
[role="spinbutton"],
|
|
108
|
+
[role="gridcell"],
|
|
109
|
+
[role="listbox"],
|
|
110
|
+
[role="scrollbar"],
|
|
111
|
+
.smwb-tooltip__wrapper,
|
|
112
|
+
.smwb-appbar__no-drag,
|
|
113
|
+
[data-no-drag]
|
|
114
|
+
) {
|
|
115
|
+
-webkit-app-region: no-drag;
|
|
116
|
+
app-region: no-drag;
|
|
117
|
+
}
|
|
118
|
+
// Dense keeps the side insets and drops the vertical padding, which the 48px height has no room for.
|
|
119
|
+
// The insets are repeated here on purpose: `responsive.less` is imported after every component and resets
|
|
120
|
+
// `.smwb-appbar.smwb-dense` at phone widths, which would otherwise beat the two longhands above.
|
|
121
|
+
&.smwb-dense {
|
|
122
|
+
padding: 0 calc(@appBarPaddingX + var(--smwb-appbar-wc-right)) 0
|
|
123
|
+
calc(@appBarPaddingX + var(--smwb-appbar-wc-left));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
42
126
|
&__inner {
|
|
43
127
|
display: flex;
|
|
44
128
|
align-items: center;
|
|
@@ -52,6 +136,12 @@
|
|
|
52
136
|
gap: @appBarActionsGap;
|
|
53
137
|
white-space: nowrap;
|
|
54
138
|
}
|
|
139
|
+
// The title may be a heading (`titleAs`): drop the UA margins and font so it
|
|
140
|
+
// looks the same as the div.
|
|
141
|
+
&__left__title {
|
|
142
|
+
margin: 0;
|
|
143
|
+
font: inherit;
|
|
144
|
+
}
|
|
55
145
|
&__right {
|
|
56
146
|
white-space: nowrap;
|
|
57
147
|
}
|
|
@@ -74,6 +164,24 @@
|
|
|
74
164
|
}
|
|
75
165
|
}
|
|
76
166
|
|
|
167
|
+
// Overlays opened from a `variant="window"` bar are portaled to `<body>`, outside the bar's own subtree, but
|
|
168
|
+
// Electron hit-tests drag regions by geometry: a dropdown drawn over the bar would be unclickable. `no-drag`
|
|
169
|
+
// is ignored outside app windows, so this is harmless for every other page. The library's own full-screen
|
|
170
|
+
// portals are listed by class because they carry no `data-smwb-overlay-layer`: a lightbox opened over the top
|
|
171
|
+
// of the bar would otherwise stay a drag region, so a backdrop click there would drag the window instead of
|
|
172
|
+
// closing it.
|
|
173
|
+
[data-smwb-overlay-layer],
|
|
174
|
+
.smwb-menu,
|
|
175
|
+
.smwb-tooltip,
|
|
176
|
+
.smwb-snackbars,
|
|
177
|
+
.smwb-chat-attachment-image__overlay,
|
|
178
|
+
.smwb-image-modal__overlay,
|
|
179
|
+
.smwb-thumb-card__preview,
|
|
180
|
+
.smwb-chat-shell {
|
|
181
|
+
-webkit-app-region: no-drag;
|
|
182
|
+
app-region: no-drag;
|
|
183
|
+
}
|
|
184
|
+
|
|
77
185
|
.smwb-appbar_color-primary {
|
|
78
186
|
background-color: var(--smui-primaryColor);
|
|
79
187
|
color: var(--smui-onPrimaryColor);
|
|
@@ -33,14 +33,17 @@
|
|
|
33
33
|
&.smwb-small {
|
|
34
34
|
font-size: @smallButtonFontSize;
|
|
35
35
|
padding: @buttonPaddingSmall;
|
|
36
|
+
min-height: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
36
37
|
}
|
|
37
38
|
&.smwb-medium {
|
|
38
39
|
font-size: @mediumButtonFontSize;
|
|
39
40
|
padding: @buttonPaddingMedium;
|
|
41
|
+
min-height: var(--smui-control-h-md, @smui-control-h-md);
|
|
40
42
|
}
|
|
41
43
|
&.smwb-large {
|
|
42
44
|
font-size: @largeButtonFontSize;
|
|
43
45
|
padding: @buttonPaddingLarge;
|
|
46
|
+
min-height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
&.smwb-contained {
|
|
@@ -52,7 +55,10 @@
|
|
|
52
55
|
}
|
|
53
56
|
&:hover {
|
|
54
57
|
background-color: var(--smui-buttonContainedHoverBg);
|
|
55
|
-
box-shadow:
|
|
58
|
+
box-shadow:
|
|
59
|
+
0 4px 22px -2px rgba(0, 0, 0, 0.2),
|
|
60
|
+
0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
|
61
|
+
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
|
56
62
|
}
|
|
57
63
|
&:disabled {
|
|
58
64
|
background-color: var(--smui-buttonDisabledBg);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
.smwb-text-field-checkbox {
|
|
2
|
-
|
|
2
|
+
min-width: 0 !important;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.smwb-checkbox {
|
|
6
|
-
// The box's size, which the native input takes too.
|
|
7
|
-
|
|
6
|
+
// The box's size, which the native input takes too. The medium default is the
|
|
7
|
+
// selection token (18px), so the component's unstyled rendering is unchanged.
|
|
8
|
+
@box-size: @smui-selection-md;
|
|
8
9
|
|
|
9
10
|
&__icon {
|
|
10
11
|
opacity: 0;
|
|
@@ -26,6 +27,10 @@
|
|
|
26
27
|
position: relative;
|
|
27
28
|
transition: all 0.2s ease-in-out;
|
|
28
29
|
&::before {
|
|
30
|
+
// The hover/active halo stays 40px at every size. It is already the box's
|
|
31
|
+
// own minimum touch target (40px >= the md row height) and scales from the
|
|
32
|
+
// box's center, so shrinking it for sm would buy nothing and drop the
|
|
33
|
+
// largest size's halo below the 22px box it is meant to surround.
|
|
29
34
|
width: 40px;
|
|
30
35
|
height: 40px;
|
|
31
36
|
border-radius: @circleBorderRadius;
|
|
@@ -123,4 +128,33 @@
|
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
}
|
|
131
|
+
|
|
132
|
+
// The size prop maps the row onto the control-height scale and the box onto the
|
|
133
|
+
// selection scale. The size class rides the wrapper (the row), so min-height
|
|
134
|
+
// goes there; the box keeps a hard height, since a checkbox box must not stretch
|
|
135
|
+
// to fill the row. The hidden native input is resized with the box so its hit
|
|
136
|
+
// area stays coincident. medium is the component default and repeats today's
|
|
137
|
+
// 18px box exactly, so unstyled rendering does not change.
|
|
138
|
+
&_size-small {
|
|
139
|
+
min-height: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
140
|
+
.smwb-checkbox__btn,
|
|
141
|
+
.smwb-checkbox__input {
|
|
142
|
+
width: @smui-selection-sm;
|
|
143
|
+
height: @smui-selection-sm;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// The medium box stays on the base rule's @box-size: @smui-selection-md
|
|
147
|
+
// read — repeating it here would only raise specificity and break consumer
|
|
148
|
+
// overrides of the default checkbox.
|
|
149
|
+
&_size-medium {
|
|
150
|
+
min-height: var(--smui-control-h-md, @smui-control-h-md);
|
|
151
|
+
}
|
|
152
|
+
&_size-large {
|
|
153
|
+
min-height: var(--smui-control-h-lg, @smui-control-h-lg);
|
|
154
|
+
.smwb-checkbox__btn,
|
|
155
|
+
.smwb-checkbox__input {
|
|
156
|
+
width: @smui-selection-lg;
|
|
157
|
+
height: @smui-selection-lg;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
126
160
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
.smwb-chip {
|
|
2
2
|
position: relative;
|
|
3
3
|
user-select: none;
|
|
4
|
-
|
|
4
|
+
// Chip's default box is 32px, which is the sm step of the control scale, not md
|
|
5
|
+
// (Chip has no large size, so sm is the only step it maps to).
|
|
6
|
+
min-height: var(--smui-control-h-sm, @smui-control-h-sm);
|
|
5
7
|
display: inline-flex;
|
|
6
8
|
align-items: center;
|
|
7
9
|
justify-content: center;
|
|
@@ -33,7 +35,10 @@
|
|
|
33
35
|
}
|
|
34
36
|
&:active {
|
|
35
37
|
background-color: var(--smui-chipsActiveBg);
|
|
36
|
-
box-shadow:
|
|
38
|
+
box-shadow:
|
|
39
|
+
0px 3px 5px -1px rgb(0 0 0 / 16%),
|
|
40
|
+
0px 1px 1px 0px rgb(0 0 0 / 14%),
|
|
41
|
+
0px 2px 3px 0px rgb(0 0 0 / 12%);
|
|
37
42
|
}
|
|
38
43
|
&.smwb-selected {
|
|
39
44
|
background-color: var(--smui-chipsSelectedBg);
|
|
@@ -47,7 +52,10 @@
|
|
|
47
52
|
}
|
|
48
53
|
&:active {
|
|
49
54
|
background-color: var(--smui-chipsActiveBg);
|
|
50
|
-
box-shadow:
|
|
55
|
+
box-shadow:
|
|
56
|
+
0px 3px 5px -1px rgb(0 0 0 / 11%),
|
|
57
|
+
0px 1px 1px 0px rgb(0 0 0 / 14%),
|
|
58
|
+
0px 2px 3px 0px rgb(0 0 0 / 12%);
|
|
51
59
|
}
|
|
52
60
|
&.smwb-selected {
|
|
53
61
|
background-color: var(--smui-chipsSelectedBg);
|
|
@@ -119,7 +127,11 @@
|
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
&_size-small {
|
|
130
|
+
// 24px is deliberately below the control scale (Fork C): it stays a literal,
|
|
131
|
+
// not a token. min-height is repeated because the base rule floors the box at
|
|
132
|
+
// the sm step (32px); without it the height alone would be clamped back up.
|
|
122
133
|
height: 24px;
|
|
134
|
+
min-height: 24px;
|
|
123
135
|
padding: 0 @smui-space-sm;
|
|
124
136
|
font-size: 0.75rem;
|
|
125
137
|
}
|