@visns-studio/visns-components 6.3.3 → 6.3.4
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/package.json +1 -1
- package/src/components/Field.jsx +10 -0
- package/src/components/Form.jsx +32 -0
- package/src/components/generic/GenericDetail.jsx +16 -0
- package/src/components/styles/Form.module.scss +73 -31
- package/src/components/styles/GenericDetail.module.scss +93 -17
- package/src/components/styles/GenericIndex.module.scss +31 -14
- package/src/components/styles/TableFilter.module.scss +96 -62
package/package.json
CHANGED
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
92
92
|
},
|
|
93
93
|
"name": "@visns-studio/visns-components",
|
|
94
|
-
"version": "6.3.
|
|
94
|
+
"version": "6.3.4",
|
|
95
95
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
96
96
|
"main": "src/index.js",
|
|
97
97
|
"files": [
|
package/src/components/Field.jsx
CHANGED
|
@@ -2306,6 +2306,11 @@ function Field({
|
|
|
2306
2306
|
data-name={settings.id}
|
|
2307
2307
|
type="radio"
|
|
2308
2308
|
className={`${styles.fi__customcheckbox} radio-input`}
|
|
2309
|
+
// Radio renderers previously ignored the
|
|
2310
|
+
// field's read-only state, leaving
|
|
2311
|
+
// `readOnlyWhen` configs claiming a lock
|
|
2312
|
+
// the UI didn't enforce.
|
|
2313
|
+
disabled={isFieldReadOnly}
|
|
2309
2314
|
value={option.id}
|
|
2310
2315
|
checked={
|
|
2311
2316
|
inputValue !== undefined &&
|
|
@@ -2336,6 +2341,11 @@ function Field({
|
|
|
2336
2341
|
data-name={settings.id}
|
|
2337
2342
|
type="radio"
|
|
2338
2343
|
className={`${styles.fi__customcheckbox} radio-input`}
|
|
2344
|
+
// Radio renderers previously ignored the
|
|
2345
|
+
// field's read-only state, leaving
|
|
2346
|
+
// `readOnlyWhen` configs claiming a lock
|
|
2347
|
+
// the UI didn't enforce.
|
|
2348
|
+
disabled={isFieldReadOnly}
|
|
2339
2349
|
value={option.id}
|
|
2340
2350
|
checked={
|
|
2341
2351
|
inputValue !== undefined &&
|
package/src/components/Form.jsx
CHANGED
|
@@ -115,6 +115,12 @@ function Form({
|
|
|
115
115
|
const [inputClass, setInputClass] = useState({});
|
|
116
116
|
const [tableData, setTableData] = useState({ columns: [], dataSource: [] });
|
|
117
117
|
const [tableProps, setTableProps] = useState({});
|
|
118
|
+
// A `save.return.type: 'table'` form (the report filter rows in
|
|
119
|
+
// GenericDetail) renders nothing at all when the query comes back empty,
|
|
120
|
+
// so "no rows matched" and "you have not run it yet" looked identical: an
|
|
121
|
+
// unchanged blank panel under a "generated successfully" toast. This
|
|
122
|
+
// separates the two so the empty result can say so.
|
|
123
|
+
const [hasQueried, setHasQueried] = useState(false);
|
|
118
124
|
const [uploadProgress, setUploadProgress] = useState(0);
|
|
119
125
|
|
|
120
126
|
// Group selection state management
|
|
@@ -2091,6 +2097,11 @@ function Form({
|
|
|
2091
2097
|
);
|
|
2092
2098
|
}
|
|
2093
2099
|
|
|
2100
|
+
// Set before the branch: an empty result is
|
|
2101
|
+
// still a result, and that is the case the
|
|
2102
|
+
// empty state exists for.
|
|
2103
|
+
setHasQueried(true);
|
|
2104
|
+
|
|
2094
2105
|
if (
|
|
2095
2106
|
res.data[formSettings.save.return.param]
|
|
2096
2107
|
?.length > 0
|
|
@@ -3300,6 +3311,27 @@ function Form({
|
|
|
3300
3311
|
/>
|
|
3301
3312
|
</div>
|
|
3302
3313
|
)}
|
|
3314
|
+
|
|
3315
|
+
{/* Empty result. Only ever after a run — before that the
|
|
3316
|
+
panel is a filter row waiting to be used, and telling
|
|
3317
|
+
the user there is nothing there would be wrong. Copy is
|
|
3318
|
+
overridable per report via `save.return.empty`. */}
|
|
3319
|
+
{hasQueried &&
|
|
3320
|
+
formSettings?.save?.return?.type === 'table' &&
|
|
3321
|
+
!(tableData?.dataSource?.length > 0) && (
|
|
3322
|
+
<div
|
|
3323
|
+
className={`${styles.formItem} ${styles.fwItem} ${styles.emptyResult}`}
|
|
3324
|
+
>
|
|
3325
|
+
<p>
|
|
3326
|
+
{formSettings.save.return.empty?.title ||
|
|
3327
|
+
'No records matched'}
|
|
3328
|
+
</p>
|
|
3329
|
+
<span>
|
|
3330
|
+
{formSettings.save.return.empty?.message ||
|
|
3331
|
+
'Nothing came back for these filters. Widen them and run the report again.'}
|
|
3332
|
+
</span>
|
|
3333
|
+
</div>
|
|
3334
|
+
)}
|
|
3303
3335
|
</form>
|
|
3304
3336
|
<div className={styles.polActions}>
|
|
3305
3337
|
{formSettings.hasOwnProperty('customButton') &&
|
|
@@ -2679,6 +2679,22 @@ function GenericDetail({
|
|
|
2679
2679
|
>
|
|
2680
2680
|
<span>{formConfig.title}</span>
|
|
2681
2681
|
</div>
|
|
2682
|
+
{/* Optional one-line subtitle. A
|
|
2683
|
+
report tab is a name and a set
|
|
2684
|
+
of controls with nothing saying
|
|
2685
|
+
what it returns; a tab that has
|
|
2686
|
+
something to say can now say
|
|
2687
|
+
it, and one that has not is
|
|
2688
|
+
unchanged. */}
|
|
2689
|
+
{formConfig.description && (
|
|
2690
|
+
<p
|
|
2691
|
+
className={
|
|
2692
|
+
styles.gridtxt__description
|
|
2693
|
+
}
|
|
2694
|
+
>
|
|
2695
|
+
{formConfig.description}
|
|
2696
|
+
</p>
|
|
2697
|
+
)}
|
|
2682
2698
|
<Form
|
|
2683
2699
|
key={`form-${activeTabConfig.id}`}
|
|
2684
2700
|
columnId={routeParams[urlParam]}
|
|
@@ -335,43 +335,54 @@ input[type='file'] {
|
|
|
335
335
|
|
|
336
336
|
|
|
337
337
|
|
|
338
|
+
/* The form's primary action (Save / View Report / Refresh).
|
|
339
|
+
|
|
340
|
+
This was a bespoke button — 1.25em type on 0.65rem padding, its own radius
|
|
341
|
+
token, its own transition curve, and a hover that swapped to pale blue on
|
|
342
|
+
blue. Sat next to `.btn` (the shared primary) in the same action bar, so the
|
|
343
|
+
two controls that are meant to read as a pair were a different height, a
|
|
344
|
+
different type size and a different hover. It is the same button as every
|
|
345
|
+
other primary in the library; it just needed to say so. */
|
|
338
346
|
.saveBtn {
|
|
339
|
-
|
|
340
|
-
display: inline-block;
|
|
341
|
-
position: relative;
|
|
342
|
-
padding: 0.65rem 1rem;
|
|
343
|
-
cursor: pointer;
|
|
344
|
-
font-size: 1rem;
|
|
345
|
-
color: var(--tertiary-color);
|
|
346
|
-
text-decoration: none;
|
|
347
|
-
overflow: hidden;
|
|
348
|
-
background: var(--primary-color);
|
|
349
|
-
border: 1px solid rgba(var(--primary-color--rgb), 1.1);
|
|
350
|
-
border-radius: var(--br);
|
|
351
|
-
outline: none;
|
|
352
|
-
transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
|
|
353
|
-
font-size: 1.25em;
|
|
354
|
-
|
|
355
|
-
&:hover {
|
|
356
|
-
color: var(--primary-color);
|
|
357
|
-
background: var(--highlight-color);
|
|
358
|
-
border: 1px solid rgba(var(--highlight-rgb), 1.05);
|
|
359
|
-
}
|
|
347
|
+
@include button-primary;
|
|
360
348
|
}
|
|
361
349
|
|
|
350
|
+
/* The inline form's action bar.
|
|
351
|
+
|
|
352
|
+
Was `position: fixed; bottom: 15px; right: 20px` with `float: left`
|
|
353
|
+
children: the buttons left the form entirely and parked in the corner of
|
|
354
|
+
the *viewport*. On a short form (the report filter rows in GenericDetail —
|
|
355
|
+
one row of dropdowns) that put "View Report" nowhere near the filters it
|
|
356
|
+
runs; on a form that returns a results grid it floated on top of the grid's
|
|
357
|
+
last rows and its horizontal scrollbar.
|
|
358
|
+
|
|
359
|
+
It is a footer to the form it belongs to, so it lives at the end of the
|
|
360
|
+
form. `sticky` keeps what the fixed positioning was actually for — the
|
|
361
|
+
action stays reachable while a long form or a 550px results grid is
|
|
362
|
+
scrolled — without detaching it from its panel. */
|
|
362
363
|
.polActions {
|
|
363
|
-
position:
|
|
364
|
-
bottom:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
364
|
+
position: sticky;
|
|
365
|
+
bottom: 0;
|
|
366
|
+
z-index: 5;
|
|
367
|
+
display: flex;
|
|
368
|
+
align-items: center;
|
|
369
|
+
justify-content: flex-end;
|
|
370
|
+
gap: var(--spacing-sm, 0.5rem);
|
|
371
|
+
width: 100%;
|
|
372
|
+
margin-top: var(--spacing-lg, 1.5rem);
|
|
373
|
+
padding: var(--spacing-sm, 0.5rem) 0;
|
|
374
|
+
/* Opaque, or the form scrolls through the bar while it is stuck. */
|
|
375
|
+
background: var(--surface-color, #fff);
|
|
376
|
+
border-top: 1px solid var(--border-color, #e1e1e1);
|
|
368
377
|
}
|
|
369
378
|
|
|
370
|
-
.
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
379
|
+
/* One primary per bar. Download / Sort / Save & Exit are alternatives to the
|
|
380
|
+
main action, not competitors: identical geometry, no fill. Previously every
|
|
381
|
+
button in here was a filled brand-blue block, so a filter row offering
|
|
382
|
+
"Download Report" and "View Report" gave no clue which one was the thing
|
|
383
|
+
you came to do. */
|
|
384
|
+
.polActions .btn {
|
|
385
|
+
@include button-secondary;
|
|
375
386
|
}
|
|
376
387
|
|
|
377
388
|
/* For in-place editing mode */
|
|
@@ -421,6 +432,37 @@ input[type='file'] {
|
|
|
421
432
|
display: none;
|
|
422
433
|
}
|
|
423
434
|
|
|
435
|
+
/* Empty result for `save.return.type: 'table'` forms. Deliberately not a
|
|
436
|
+
card and not an alert: an empty report is an ordinary outcome, so it is a
|
|
437
|
+
quiet block of centred text on the panel it would have filled, drawn with
|
|
438
|
+
the same hairline the rest of the page separates things with. */
|
|
439
|
+
.emptyResult {
|
|
440
|
+
display: flex;
|
|
441
|
+
flex-direction: column;
|
|
442
|
+
align-items: center;
|
|
443
|
+
justify-content: center;
|
|
444
|
+
gap: var(--spacing-xs, 0.25rem);
|
|
445
|
+
padding: var(--spacing-2xl, 3rem) var(--spacing-md, 1rem);
|
|
446
|
+
text-align: center;
|
|
447
|
+
border: 1px dashed var(--border-color, #e1e1e1);
|
|
448
|
+
border-radius: var(--radius-md, 10px);
|
|
449
|
+
background: var(--alternate-color, transparent);
|
|
450
|
+
|
|
451
|
+
p {
|
|
452
|
+
margin: 0;
|
|
453
|
+
font-size: var(--font-size-md, 0.9375rem);
|
|
454
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
455
|
+
color: var(--heading-color, inherit);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
span {
|
|
459
|
+
max-width: 42ch;
|
|
460
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
461
|
+
line-height: 1.5;
|
|
462
|
+
color: var(--muted-color, #6e7276);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
424
466
|
.buttonContainer {
|
|
425
467
|
display: flex;
|
|
426
468
|
justify-content: center;
|
|
@@ -86,15 +86,31 @@
|
|
|
86
86
|
gap: 0.5rem;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/* The tab rail. Identical spec to `.grid__subnav` in GenericIndex.module.scss
|
|
90
|
+
— the two pages share one rail, so keep them in step.
|
|
91
|
+
|
|
92
|
+
It was a white panel under a 50px brand-tinted blur, holding one tinted blue
|
|
93
|
+
pill per tab. Every item therefore carried the same weight as the selected
|
|
94
|
+
one, and a seven-tab rail (the reports page) read as a stack of seven
|
|
95
|
+
buttons rather than as navigation with one thing chosen. 6.3's answer
|
|
96
|
+
everywhere else on the page is a flat surface, a hairline and quiet ink, so
|
|
97
|
+
that is what the rail gets: unselected tabs are plain text on the panel, and
|
|
98
|
+
the brand blue is spent once, on the tab you are actually on. */
|
|
89
99
|
.grid__subnav {
|
|
100
|
+
/* `flex: 1` (basis 0) against `.grid__subcontent`'s `flex: 0 1 80%` is
|
|
101
|
+
left exactly as it was: `.grid__subrow` is `flex-wrap: wrap`, so a
|
|
102
|
+
flex-basis here large enough to overflow the row would wrap the content
|
|
103
|
+
panel onto its own line rather than shrink it. Only the treatment
|
|
104
|
+
changes below. */
|
|
90
105
|
flex: 1;
|
|
91
|
-
background:
|
|
106
|
+
background: var(--surface-color, #fff);
|
|
107
|
+
border: 1px solid var(--border-color, #e1e1e1);
|
|
92
108
|
border-radius: var(--br);
|
|
93
109
|
box-sizing: border-box;
|
|
94
|
-
padding:
|
|
110
|
+
padding: var(--spacing-xs, 0.25rem);
|
|
95
111
|
margin: 8px 0;
|
|
96
112
|
height: auto;
|
|
97
|
-
box-shadow:
|
|
113
|
+
box-shadow: none;
|
|
98
114
|
}
|
|
99
115
|
|
|
100
116
|
.grid__subnav > ul {
|
|
@@ -108,32 +124,54 @@
|
|
|
108
124
|
|
|
109
125
|
.grid__subnav > ul li {
|
|
110
126
|
width: 100%;
|
|
111
|
-
margin-bottom:
|
|
127
|
+
margin-bottom: var(--spacing-xs, 0.25rem);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.grid__subnav > ul li:last-child {
|
|
131
|
+
margin-bottom: 0;
|
|
112
132
|
}
|
|
113
133
|
|
|
114
134
|
.grid__subnav > ul li a {
|
|
115
135
|
width: 100%;
|
|
116
|
-
|
|
136
|
+
/* 0.35rem was a 5px-tall hit area for a control people click all day. */
|
|
137
|
+
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
|
|
117
138
|
box-sizing: border-box;
|
|
118
139
|
display: block;
|
|
119
140
|
text-decoration: none;
|
|
120
|
-
background:
|
|
121
|
-
color: var(--
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
background: none;
|
|
142
|
+
color: var(--text-color, #374151);
|
|
143
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
144
|
+
font-weight: var(--font-weight-medium, 500);
|
|
145
|
+
line-height: 1.35;
|
|
146
|
+
border-radius: var(--radius-sm, 6px);
|
|
147
|
+
transition:
|
|
148
|
+
background-color var(--speed, 0.18s) var(--ease, ease),
|
|
149
|
+
color var(--speed, 0.18s) var(--ease, ease);
|
|
125
150
|
cursor: pointer;
|
|
126
151
|
}
|
|
127
152
|
|
|
128
153
|
.grid__subnav > ul li:hover a {
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
/* Hover is a hint, not a commitment. It used to fill solid brand blue —
|
|
155
|
+
indistinguishable from the selected tab, so passing the mouse across the
|
|
156
|
+
rail made it look as though the selection was following the cursor. */
|
|
157
|
+
background: var(--hover-color, rgba(0, 0, 0, 0.04));
|
|
158
|
+
color: var(--heading-color, inherit);
|
|
131
159
|
}
|
|
132
160
|
|
|
133
161
|
.grid__subnav > ul li .subactive {
|
|
134
|
-
font-weight:
|
|
162
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
135
163
|
background: var(--primary-color);
|
|
136
|
-
|
|
164
|
+
/* Was --background-color, the page's off-white; white is what the button
|
|
165
|
+
and nav-pill treatments elsewhere put on this blue. */
|
|
166
|
+
color: #fff;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* `outline: none` used to sit on the link with nothing put back, so the rail
|
|
170
|
+
was unusable by keyboard. The app's own ring token, same as every other
|
|
171
|
+
control. */
|
|
172
|
+
.grid__subnav > ul li a:focus-visible {
|
|
173
|
+
outline: none;
|
|
174
|
+
box-shadow: var(--focus-ring, 0 0 0 3px rgba(0, 118, 192, 0.32));
|
|
137
175
|
}
|
|
138
176
|
|
|
139
177
|
.grid__minheight {
|
|
@@ -146,9 +184,12 @@
|
|
|
146
184
|
|
|
147
185
|
.grid__subcontent {
|
|
148
186
|
flex: 0 1 80%;
|
|
149
|
-
background: var(--
|
|
187
|
+
background: var(--surface-color, #fff);
|
|
150
188
|
border-radius: var(--br);
|
|
151
|
-
|
|
189
|
+
/* Was the brand blue at 5% — a tint so faint the panel had no edge at all
|
|
190
|
+
while the rail beside it did. The shared hairline, same as every other
|
|
191
|
+
surface on the page. */
|
|
192
|
+
border: 1px solid var(--border-color, #e1e1e1);
|
|
152
193
|
box-sizing: border-box;
|
|
153
194
|
padding: 2px;
|
|
154
195
|
margin: 8px 0;
|
|
@@ -163,6 +204,24 @@
|
|
|
163
204
|
margin: 0 0 30px 0;
|
|
164
205
|
}
|
|
165
206
|
|
|
207
|
+
/* The tab panel's own inset.
|
|
208
|
+
|
|
209
|
+
`.gridtxt` had no rule at all, and its container (`.grid__subcontent`,
|
|
210
|
+
`.grid__full`) carries `padding: 2px` — so a panel's section heading and any
|
|
211
|
+
form inside it sat 2px from the panel border. Only the overview `<ul>` was
|
|
212
|
+
readable, because it padded itself. On the reports page that meant the
|
|
213
|
+
filter row's dropdowns and date pickers were flush against the panel edge.
|
|
214
|
+
|
|
215
|
+
The inset belongs to the panel, not to one child of it, so it is stated
|
|
216
|
+
here once and the `<ul>` below gives up its horizontal padding to match.
|
|
217
|
+
The `<ul>`'s vertical padding stays: with several heading/list pairs in one
|
|
218
|
+
`.gridtxt` (the overview tabs) that is what separates one section from the
|
|
219
|
+
next. */
|
|
220
|
+
.gridtxt {
|
|
221
|
+
padding: var(--spacing-md, 1rem) var(--spacing-lg, 1.5rem)
|
|
222
|
+
var(--spacing-lg, 1.5rem);
|
|
223
|
+
}
|
|
224
|
+
|
|
166
225
|
.gridtxt__header {
|
|
167
226
|
width: 100%;
|
|
168
227
|
display: block;
|
|
@@ -192,6 +251,21 @@
|
|
|
192
251
|
font-weight: 700;
|
|
193
252
|
}
|
|
194
253
|
|
|
254
|
+
/* Optional one-line subtitle under a section heading (GenericDetail renders it
|
|
255
|
+
from a tab's `description`). Sits in the heading's own space — it belongs to
|
|
256
|
+
the label, not to the content — so it takes over the heading's bottom margin
|
|
257
|
+
rather than adding a third gap. */
|
|
258
|
+
.gridtxt__description {
|
|
259
|
+
/* Pulls back half of the heading's 1rem bottom margin, so the subtitle sits
|
|
260
|
+
close under its heading and the whole block is separated from the
|
|
261
|
+
content below rather than floating between the two. */
|
|
262
|
+
margin: calc(-1 * var(--spacing-sm, 0.5rem)) 0 var(--spacing-lg, 1.5rem);
|
|
263
|
+
max-width: 70ch;
|
|
264
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
265
|
+
line-height: 1.55;
|
|
266
|
+
color: var(--muted-color, #6e7276);
|
|
267
|
+
}
|
|
268
|
+
|
|
195
269
|
.gridtxt > ul {
|
|
196
270
|
width: 100%;
|
|
197
271
|
display: flex;
|
|
@@ -200,7 +274,9 @@
|
|
|
200
274
|
flex-wrap: wrap;
|
|
201
275
|
list-style: none;
|
|
202
276
|
box-sizing: border-box;
|
|
203
|
-
padding
|
|
277
|
+
/* Horizontal padding removed — `.gridtxt` owns the panel inset now (see
|
|
278
|
+
the note there). The vertical padding separates stacked sections. */
|
|
279
|
+
padding: 0.85rem 0;
|
|
204
280
|
margin: 0;
|
|
205
281
|
}
|
|
206
282
|
|
|
@@ -114,15 +114,19 @@
|
|
|
114
114
|
gap: 0.5rem;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/* The tab rail. Identical spec to `.grid__subnav` in GenericDetail.module.scss
|
|
118
|
+
— the two pages share one rail, so keep them in step; the reasoning for the
|
|
119
|
+
treatment is written out there. */
|
|
117
120
|
.grid__subnav {
|
|
118
121
|
flex: 1;
|
|
119
|
-
background:
|
|
122
|
+
background: var(--surface-color, #fff);
|
|
123
|
+
border: 1px solid var(--border-color, #e1e1e1);
|
|
120
124
|
border-radius: var(--br);
|
|
121
125
|
box-sizing: border-box;
|
|
122
|
-
padding:
|
|
126
|
+
padding: var(--spacing-xs, 0.25rem);
|
|
123
127
|
margin: 8px 0;
|
|
124
128
|
height: auto;
|
|
125
|
-
box-shadow:
|
|
129
|
+
box-shadow: none;
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
.grid__subnav > ul {
|
|
@@ -136,32 +140,45 @@
|
|
|
136
140
|
|
|
137
141
|
.grid__subnav > ul li {
|
|
138
142
|
width: 100%;
|
|
139
|
-
margin-bottom:
|
|
143
|
+
margin-bottom: var(--spacing-xs, 0.25rem);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.grid__subnav > ul li:last-child {
|
|
147
|
+
margin-bottom: 0;
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
.grid__subnav > ul li a {
|
|
143
151
|
width: 100%;
|
|
144
|
-
padding: 0.
|
|
152
|
+
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
|
|
145
153
|
box-sizing: border-box;
|
|
146
154
|
display: block;
|
|
147
155
|
text-decoration: none;
|
|
148
|
-
background:
|
|
149
|
-
color: var(--
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
background: none;
|
|
157
|
+
color: var(--text-color, #374151);
|
|
158
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
159
|
+
font-weight: var(--font-weight-medium, 500);
|
|
160
|
+
line-height: 1.35;
|
|
161
|
+
border-radius: var(--radius-sm, 6px);
|
|
162
|
+
transition:
|
|
163
|
+
background-color var(--speed, 0.18s) var(--ease, ease),
|
|
164
|
+
color var(--speed, 0.18s) var(--ease, ease);
|
|
153
165
|
cursor: pointer;
|
|
154
166
|
}
|
|
155
167
|
|
|
156
168
|
.grid__subnav > ul li:hover a {
|
|
157
|
-
background: var(--
|
|
158
|
-
color: var(--
|
|
169
|
+
background: var(--hover-color, rgba(0, 0, 0, 0.04));
|
|
170
|
+
color: var(--heading-color, inherit);
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
.grid__subnav > ul li .subactive {
|
|
162
|
-
font-weight:
|
|
174
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
163
175
|
background: var(--primary-color);
|
|
164
|
-
color:
|
|
176
|
+
color: #fff;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.grid__subnav > ul li a:focus-visible {
|
|
180
|
+
outline: none;
|
|
181
|
+
box-shadow: var(--focus-ring, 0 0 0 3px rgba(0, 118, 192, 0.32));
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
.grid__subnav__alternate {
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tab rail's own stylesheet, which predates the 6.3 token language: it was
|
|
3
|
+
* still drawing its own card (a hardcoded rgba drop shadow and radius) and its
|
|
4
|
+
* own type scale (0.85/0.9rem literals) around items that the host surface —
|
|
5
|
+
* `.grid__subnav` in GenericIndex/GenericDetail — already frames. Two nested
|
|
6
|
+
* cards, two shadows, and a rail whose type did not match anything else on the
|
|
7
|
+
* page. Everything here now reads the same tokens as the rest of the library,
|
|
8
|
+
* and the framing is left to the surface it sits on.
|
|
9
|
+
*
|
|
10
|
+
* Literal fallbacks throughout: a bare `var()` for a token a consuming app has
|
|
11
|
+
* not declared is invalid at computed-value time and the whole declaration is
|
|
12
|
+
* dropped, which is exactly how a rail like this loses its padding.
|
|
13
|
+
*/
|
|
14
|
+
|
|
1
15
|
.tableFilterContainer {
|
|
2
16
|
width: 100%;
|
|
3
17
|
position: relative;
|
|
@@ -9,11 +23,11 @@
|
|
|
9
23
|
list-style: none;
|
|
10
24
|
padding: 0;
|
|
11
25
|
margin: 0;
|
|
12
|
-
font-size: 0.
|
|
26
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
13
27
|
width: 100%;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
/* No radius, no shadow, no `overflow: hidden`. The panel around this list
|
|
29
|
+
supplies the surface; the clipping additionally cut the focus ring off
|
|
30
|
+
the first and last items. */
|
|
17
31
|
}
|
|
18
32
|
|
|
19
33
|
/* Parent category styling */
|
|
@@ -29,19 +43,23 @@
|
|
|
29
43
|
display: flex;
|
|
30
44
|
justify-content: space-between;
|
|
31
45
|
align-items: center;
|
|
32
|
-
padding:
|
|
33
|
-
|
|
34
|
-
font-
|
|
46
|
+
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
|
|
47
|
+
border-radius: var(--radius-sm, 6px);
|
|
48
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
49
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
35
50
|
background-color: var(--primary-color, #000);
|
|
36
|
-
color:
|
|
37
|
-
|
|
51
|
+
color: #fff;
|
|
52
|
+
/* Was `all 0.2s`, which animates layout properties too. */
|
|
53
|
+
transition:
|
|
54
|
+
background-color var(--speed, 0.18s) var(--ease, ease),
|
|
55
|
+
color var(--speed, 0.18s) var(--ease, ease);
|
|
38
56
|
position: relative;
|
|
39
57
|
text-decoration: none;
|
|
40
58
|
}
|
|
41
59
|
|
|
42
60
|
.parentLink:hover {
|
|
43
|
-
background-color: var(--
|
|
44
|
-
color:
|
|
61
|
+
background-color: var(--primary-color-darker, #222) !important;
|
|
62
|
+
color: #fff !important;
|
|
45
63
|
text-decoration: none;
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -63,7 +81,9 @@
|
|
|
63
81
|
overflow: hidden;
|
|
64
82
|
transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
|
|
65
83
|
opacity: 0;
|
|
66
|
-
|
|
84
|
+
/* Flush with the rail. The child links carry their own hover surface now,
|
|
85
|
+
so a tint behind the whole submenu only made a second panel edge. */
|
|
86
|
+
background: none;
|
|
67
87
|
}
|
|
68
88
|
|
|
69
89
|
.visibleMenu {
|
|
@@ -74,7 +94,7 @@
|
|
|
74
94
|
.childItem {
|
|
75
95
|
margin: 0;
|
|
76
96
|
position: relative;
|
|
77
|
-
border-bottom: 1px solid
|
|
97
|
+
border-bottom: 1px solid var(--border-color, #e1e1e1);
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
.childItem:last-child {
|
|
@@ -82,18 +102,20 @@
|
|
|
82
102
|
}
|
|
83
103
|
|
|
84
104
|
.childLink {
|
|
85
|
-
padding:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
font-
|
|
105
|
+
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem) var(--spacing-sm, 0.5rem)
|
|
106
|
+
var(--spacing-xl, 1.75rem);
|
|
107
|
+
background: none;
|
|
108
|
+
color: var(--text-color, #333);
|
|
109
|
+
font-weight: var(--font-weight-regular, 400);
|
|
110
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
111
|
+
border-radius: var(--radius-sm, 6px);
|
|
90
112
|
display: block;
|
|
91
113
|
text-decoration: none;
|
|
92
114
|
}
|
|
93
115
|
|
|
94
116
|
.childLink:hover {
|
|
95
117
|
background-color: var(--hover-color, #e8e8e8) !important;
|
|
96
|
-
color: var(--
|
|
118
|
+
color: var(--heading-color, #000) !important;
|
|
97
119
|
text-decoration: none;
|
|
98
120
|
}
|
|
99
121
|
|
|
@@ -104,37 +126,55 @@
|
|
|
104
126
|
color: rgba(var(--paragraph-color-rgb, 153, 153, 153), 0.6);
|
|
105
127
|
}
|
|
106
128
|
|
|
107
|
-
/* Active states
|
|
129
|
+
/* Active states. The brand fill is the one loud thing in the rail, and it
|
|
130
|
+
marks exactly one item — which is what makes it readable as a selection
|
|
131
|
+
rather than as decoration. */
|
|
108
132
|
.subactive {
|
|
109
|
-
font-weight: 600;
|
|
133
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
110
134
|
background: var(--primary-color, #000) !important;
|
|
111
|
-
|
|
135
|
+
/* Was --tertiary-color, which several projects set to their page
|
|
136
|
+
off-white; white is what sits on this blue elsewhere. */
|
|
137
|
+
color: #fff !important;
|
|
112
138
|
}
|
|
113
139
|
|
|
114
140
|
.subactivechildren {
|
|
115
|
-
font-weight: 500;
|
|
116
|
-
background-color: var(--
|
|
141
|
+
font-weight: var(--font-weight-medium, 500);
|
|
142
|
+
background-color: var(--primary-color-light, #f0f0f0) !important;
|
|
117
143
|
color: var(--primary-color, #000) !important;
|
|
118
144
|
}
|
|
119
145
|
|
|
120
|
-
/* Base link styling
|
|
146
|
+
/* Base link styling. Unselected tabs are text on the panel, not tinted
|
|
147
|
+
blocks — see the note on `.grid__subnav` in GenericDetail.module.scss. */
|
|
121
148
|
.link {
|
|
122
149
|
display: block;
|
|
123
|
-
padding:
|
|
150
|
+
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
|
|
124
151
|
text-decoration: none;
|
|
125
|
-
background:
|
|
126
|
-
color: var(--
|
|
127
|
-
font-size: 0.
|
|
128
|
-
|
|
152
|
+
background: none;
|
|
153
|
+
color: var(--text-color, #333);
|
|
154
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
155
|
+
font-weight: var(--font-weight-medium, 500);
|
|
156
|
+
border-radius: var(--radius-sm, 6px);
|
|
157
|
+
transition:
|
|
158
|
+
background-color var(--speed, 0.18s) var(--ease, ease),
|
|
159
|
+
color var(--speed, 0.18s) var(--ease, ease);
|
|
129
160
|
cursor: pointer;
|
|
130
161
|
}
|
|
131
162
|
|
|
132
163
|
.link:hover {
|
|
133
164
|
background: var(--hover-color, #e8e8e8) !important;
|
|
134
|
-
|
|
165
|
+
/* Was the brand blue, which on hover made an unselected tab look like the
|
|
166
|
+
selected one. */
|
|
167
|
+
color: var(--heading-color, #000) !important;
|
|
135
168
|
text-decoration: none;
|
|
136
169
|
}
|
|
137
170
|
|
|
171
|
+
.link:focus-visible,
|
|
172
|
+
.childLink:focus-visible,
|
|
173
|
+
.parentLink:focus-visible {
|
|
174
|
+
outline: none;
|
|
175
|
+
box-shadow: var(--focus-ring, 0 0 0 3px rgba(0, 118, 192, 0.32));
|
|
176
|
+
}
|
|
177
|
+
|
|
138
178
|
.activetab button {
|
|
139
179
|
font-weight: bold;
|
|
140
180
|
background: var(--hover-color, #e0e0e0) !important;
|
|
@@ -146,19 +186,20 @@
|
|
|
146
186
|
display: none;
|
|
147
187
|
align-items: center;
|
|
148
188
|
justify-content: space-between;
|
|
149
|
-
padding:
|
|
189
|
+
padding: var(--spacing-sm, 0.75rem) var(--spacing-md, 1rem);
|
|
150
190
|
background: var(--primary-color, #000);
|
|
151
|
-
color:
|
|
152
|
-
border-radius:
|
|
191
|
+
color: #fff;
|
|
192
|
+
border-radius: var(--radius-sm, 6px);
|
|
153
193
|
cursor: pointer;
|
|
154
|
-
margin-bottom:
|
|
194
|
+
margin-bottom: var(--spacing-sm, 0.5rem);
|
|
155
195
|
border: none;
|
|
156
|
-
box-shadow: 0 1px 3px rgba(
|
|
196
|
+
box-shadow: var(--shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.2));
|
|
157
197
|
}
|
|
158
198
|
|
|
159
199
|
.activeFilterLabel {
|
|
160
|
-
font-weight: 600;
|
|
161
|
-
|
|
200
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
201
|
+
font-size: var(--font-size-sm, 0.8125rem);
|
|
202
|
+
color: #fff;
|
|
162
203
|
}
|
|
163
204
|
|
|
164
205
|
.mobileMenuIcon {
|
|
@@ -175,7 +216,7 @@
|
|
|
175
216
|
display: block;
|
|
176
217
|
height: 2px;
|
|
177
218
|
width: 100%;
|
|
178
|
-
background-color:
|
|
219
|
+
background-color: #fff;
|
|
179
220
|
border-radius: 2px;
|
|
180
221
|
transition: all 0.3s ease;
|
|
181
222
|
}
|
|
@@ -206,20 +247,17 @@
|
|
|
206
247
|
display: none; /* Hide hamburger menu on tablets */
|
|
207
248
|
}
|
|
208
249
|
|
|
209
|
-
/*
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
250
|
+
/* Roomier tap targets. Only the padding moves: the literal 0.85/0.9rem
|
|
251
|
+
sizes that used to sit here re-declared the rail's type at a scale
|
|
252
|
+
nothing else on the page uses, so the labels changed size at 1024px for
|
|
253
|
+
no reason. Density is a padding question. */
|
|
254
|
+
.parentLink,
|
|
215
255
|
.link {
|
|
216
|
-
padding:
|
|
217
|
-
font-size: 0.85rem;
|
|
256
|
+
padding: 0.65rem var(--spacing-md, 1rem);
|
|
218
257
|
}
|
|
219
258
|
|
|
220
259
|
.childLink {
|
|
221
|
-
padding:
|
|
222
|
-
font-size: 0.85rem;
|
|
260
|
+
padding: 0.65rem var(--spacing-md, 1rem) 0.65rem var(--spacing-xl, 1.75rem);
|
|
223
261
|
}
|
|
224
262
|
}
|
|
225
263
|
|
|
@@ -240,25 +278,21 @@
|
|
|
240
278
|
display: block;
|
|
241
279
|
max-height: 1000px;
|
|
242
280
|
overflow-y: auto;
|
|
243
|
-
|
|
244
|
-
border
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
.parentLink {
|
|
250
|
-
padding: 10px 16px; /* Slightly larger touch targets for mobile */
|
|
251
|
-
font-size: 0.9rem;
|
|
281
|
+
padding: var(--spacing-xs, 0.25rem);
|
|
282
|
+
border: 1px solid var(--border-color, #e1e1e1);
|
|
283
|
+
border-radius: var(--br, 8px);
|
|
284
|
+
margin-bottom: var(--spacing-sm, 0.5rem);
|
|
285
|
+
box-shadow: var(--shadow-sm, 0 2px 5px rgba(0, 0, 0, 0.1));
|
|
252
286
|
}
|
|
253
287
|
|
|
288
|
+
/* Larger tap targets on a phone; the type scale is left alone, as above. */
|
|
289
|
+
.parentLink,
|
|
254
290
|
.link {
|
|
255
|
-
padding:
|
|
256
|
-
font-size: 0.85rem;
|
|
291
|
+
padding: 0.75rem var(--spacing-md, 1rem);
|
|
257
292
|
}
|
|
258
293
|
|
|
259
294
|
.childLink {
|
|
260
|
-
padding:
|
|
261
|
-
font-size: 0.85rem;
|
|
295
|
+
padding: 0.75rem var(--spacing-md, 1rem) 0.75rem var(--spacing-xl, 1.75rem);
|
|
262
296
|
}
|
|
263
297
|
|
|
264
298
|
.collapsibleMenu {
|