@smwb/ui-styles 2.6.0 → 2.7.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 CHANGED
@@ -117,6 +117,23 @@ value for both modes, so a theme that makes `@warningColor` lighter, or any of t
117
117
  changes the numbers: re-check them there. `color="secondary"` is the one name that falls short in the default dark
118
118
  theme (2.65:1): use a status for state.
119
119
 
120
+ #### IdentityBadge colours
121
+
122
+ `IdentityBadge` is a frame with no fill, so its colour is a border, an icon and 11px of text. It reads one custom
123
+ property, `--smwb-identity-badge-accent`, which the component sets from its `accent` prop; without it (or with an empty
124
+ one) the badge resolves `--smwb-identity-badge-color` to `@identityBadgeColor`, `var(--smui-onSurfaceVariant)` —
125
+ neutral, following the dark theme. No status token (`infoColor`, `successColor`, `warningColor`, `errorColor`) appears
126
+ in the badge's rules: the marker must not read as a state the way `StatusDot` does. An accent is any CSS colour, so its
127
+ contrast is the caller's problem: at `@identityBadgeFontSize` (11px) pick one that reaches 4.5:1 against the surface it
128
+ sits on.
129
+
130
+ The box comes from `@identityBadgeHeight` (18px), `@identityBadgePaddingX` (4px), `@identityBadgeGap` (2px, icon to
131
+ text), `@identityBadgeIconSize` (12px), `@identityBadgeBorderWidth` and `@identityBadgeRadius`; the text from
132
+ `@identityBadgeFontFamily` (a monospace stack), `@identityBadgeFontSize` and `@identityBadgeFontWeight`; the row of a
133
+ group from `@identityBadgeGroupGap` (4px). All are `theme.config` variables, and the colour is the only one that reads a
134
+ `--smui-*` runtime token. Under forced colours the frame and the text draw in `CanvasText`, and a clickable "+N" in
135
+ `ButtonText`.
136
+
120
137
  #### QrCode colours
121
138
 
122
139
  `QrCode` never reads theme tokens for the code itself: the modules are always `@qrCodeDarkColor`
@@ -0,0 +1,2 @@
1
+ @import (reference) "../../_prelude.less";
2
+ @import "./identityBadge.less";
@@ -0,0 +1,110 @@
1
+ // A compact identity marker: an outlined frame with no fill, a glyph on the left and a
2
+ // short monospace text on the right. It must not read as a status, so its colour is the
3
+ // caller's accent or the theme's neutral — never a status token — and the frame, not a
4
+ // fill, carries it. One size, one look: no modifier classes.
5
+ .smwb-identity-badge {
6
+ --smwb-identity-badge-color: var(--smwb-identity-badge-accent, @identityBadgeColor);
7
+ display: inline-flex;
8
+ align-items: center;
9
+ gap: @identityBadgeGap;
10
+ flex: none;
11
+ box-sizing: border-box;
12
+ height: @identityBadgeHeight;
13
+ padding: 0 @identityBadgePaddingX;
14
+ vertical-align: middle;
15
+ white-space: nowrap;
16
+ border: @identityBadgeBorderWidth solid var(--smwb-identity-badge-color);
17
+ border-radius: @identityBadgeRadius;
18
+ background-color: transparent;
19
+ color: var(--smwb-identity-badge-color);
20
+ font-family: @identityBadgeFontFamily;
21
+ font-size: @identityBadgeFontSize;
22
+ font-weight: @identityBadgeFontWeight;
23
+ line-height: 1;
24
+
25
+ &__icon {
26
+ display: inline-flex;
27
+ flex: none;
28
+ align-items: center;
29
+ justify-content: center;
30
+ width: @identityBadgeIconSize;
31
+ height: @identityBadgeIconSize;
32
+ overflow: hidden;
33
+
34
+ // The caller picks the icon's own size, so the box clamps it: an <Icon size={20}> is scaled
35
+ // into the 12px slot instead of stretching the badge's fixed height. The Icon's wrapper
36
+ // takes the whole box, so that its glyph has a definite size to be clamped to.
37
+ > .smwb-icon__wrapper {
38
+ width: 100%;
39
+ height: 100%;
40
+ }
41
+
42
+ svg,
43
+ img {
44
+ max-width: 100%;
45
+ max-height: 100%;
46
+ }
47
+
48
+ // A font glyph sizes itself with an inline font-size, which only !important can take over.
49
+ .material-symbols-outlined {
50
+ font-size: @identityBadgeIconSize !important;
51
+ }
52
+ }
53
+ }
54
+
55
+ .smwb-identity-badge-group {
56
+ display: inline-flex;
57
+ align-items: center;
58
+ gap: @identityBadgeGroupGap;
59
+ vertical-align: middle;
60
+
61
+ // The children past `max` are drawn for hydration and hidden: a server that left them
62
+ // out would leave the browser without nodes to hydrate them from.
63
+ &__hidden {
64
+ display: none;
65
+ }
66
+
67
+ // A clickable "+N" is a real button, so a keyboard reaches it. normalize.css strips a
68
+ // button's looks and its outline, so both come back here.
69
+ button&__surplus {
70
+ position: relative; // holds the coarse-pointer hit area
71
+ margin: 0;
72
+ appearance: none;
73
+ background-color: transparent;
74
+ cursor: pointer;
75
+
76
+ &:focus-visible {
77
+ outline: 2px solid var(--smui-primaryColor);
78
+ outline-offset: 2px;
79
+ }
80
+
81
+ // A finger needs a 44px target and the badge must keep its 18px row, so the hit area
82
+ // hangs off a pseudo-element, centred over the button: the row does not grow
83
+ // (SelectField's chip-delete precedent).
84
+ @media (pointer: coarse) {
85
+ &::after {
86
+ content: "";
87
+ position: absolute;
88
+ top: 50%;
89
+ left: 50%;
90
+ width: var(--smui-control-h-sm, @smui-control-h-sm-coarse);
91
+ height: var(--smui-control-h-sm, @smui-control-h-sm-coarse);
92
+ transform: translate(-50%, -50%);
93
+ }
94
+ }
95
+ }
96
+ }
97
+
98
+ // Forced colours drop the accent: draw the frame and the text in the text colour, and a
99
+ // clickable "+N" in the button colour.
100
+ @media (forced-colors: active) {
101
+ .smwb-identity-badge {
102
+ border-color: CanvasText;
103
+ color: CanvasText;
104
+ }
105
+
106
+ button.smwb-identity-badge-group__surplus {
107
+ border-color: ButtonText;
108
+ color: ButtonText;
109
+ }
110
+ }
@@ -15,6 +15,7 @@
15
15
  @import "./components/meter/meter.less";
16
16
  @import "./components/diffStat/diffStat.less";
17
17
  @import "./components/statusDot/statusDot.less";
18
+ @import "./components/identityBadge/identityBadge.less";
18
19
  @import "./components/qrCode/qrCode.less";
19
20
  @import "./components/radioButton/radioButton.less";
20
21
  @import "./components/sidebar/sidebar.less";
@@ -204,6 +204,20 @@
204
204
  @statusDotDiamondRotation: 45deg; // corner-up, the diamond of the onreel thread marker
205
205
  @statusDotDiamondRadius: @smui-radius-none; // sharp corners; the dot's are a circle
206
206
 
207
+ // A compact identity marker sits inside a dense row, so its height is off-grid and below
208
+ // the control scale on purpose: one 14px line at the DagView node's line-height 1.3.
209
+ @identityBadgeHeight: 18px;
210
+ @identityBadgePaddingX: @smui-space-xs; // 4px
211
+ @identityBadgeGap: @smui-space-xxs; // 2px, icon to text
212
+ @identityBadgeIconSize: 12px; // @smui-space-3
213
+ @identityBadgeBorderWidth: 1px;
214
+ @identityBadgeRadius: @smui-radius-sm;
215
+ @identityBadgeFontFamily: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
216
+ @identityBadgeFontSize: 11px; // off-grid
217
+ @identityBadgeFontWeight: 500;
218
+ @identityBadgeColor: ~"var(--smui-onSurfaceVariant)"; // neutral, follows the dark theme; never a status token
219
+ @identityBadgeGroupGap: @smui-space-xs; // 4px between badges
220
+
207
221
  // A QR code is always dark modules on a white square — never theme tokens, so no
208
222
  // theme (or forced-colours mode, see the component's print/forced-color-adjust) can
209
223
  // invert it.
@@ -35,6 +35,8 @@
35
35
  // - ProgressIndicator: indicator diameter (28px), not a control box
36
36
  // - StatusDot: decorative dot (@statusDotSizeSm/Md); also uses the
37
37
  // _size-sm suffix, a different class convention
38
+ // - IdentityBadge: compact identity marker (@identityBadgeHeight 18px),
39
+ // not a control — it must fit a dense TreeView row and a DagView node
38
40
  // - Slider: size scales track thickness and thumb diameter, not a
39
41
  // control height
40
42
  // - Modal: size selects dialog width, not control height
@@ -53,7 +55,8 @@
53
55
  // Menu dense items, List dense rows, and the targets the controls above do not
54
56
  // cover: Composer icon buttons, Breadcrumbs "..." button, DagView zoom buttons,
55
57
  // Slider rail and thumb zones, SelectField clear button and chip delete zones, Sheet
56
- // header buttons, Table sort control, DatePicker adornment button). A mouse keeps the sizes above.
58
+ // header buttons, Table sort control, DatePicker adornment button, IdentityBadgeGroup's
59
+ // clickable "+N"). A mouse keeps the sizes above.
57
60
  // Still exempt on touch: the --filled and --inline fields, the compact Toggle
58
61
  // (capped at @toggleCompactMaxHeight) and a small Chip that is neither a button
59
62
  // nor a link.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smwb/ui-styles",
3
- "version": "2.6.0",
3
+ "version": "2.7.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": [