@apliteni/apliteni-ui 0.104.0 → 0.105.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/guidelines/dashboards-and-reports.md +77 -0
- package/guidelines/iconography.md +1 -1
- package/guidelines/stat-bands.md +10 -8
- package/guidelines/the-page.md +2 -2
- package/package.json +1 -1
- package/react/dist/index.css +3 -0
- package/src/assets/icons.js +10 -0
- package/src/components/stat.js +11 -2
- package/src/styles/card.css +0 -1
- package/src/styles/filter-bar.css +21 -3
- package/src/styles/layout.css +37 -4
- package/src/styles/stat.css +14 -0
- package/src/styles/table.css +62 -2
- package/src/styles/tap-zone.css +3 -0
- package/src/tokens/tokens.css +1 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Dashboards and reports
|
|
2
|
+
|
|
3
|
+
## Build a dashboard for one screen
|
|
4
|
+
|
|
5
|
+
<!-- rule: fast-glance -->
|
|
6
|
+
|
|
7
|
+
**Rule:** Answer “is anything wrong, and what changed” in one screen, without scrolling.
|
|
8
|
+
|
|
9
|
+
**Why:** A dashboard is read between other work: below the fold is not read.
|
|
10
|
+
|
|
11
|
+
**Except:** A phone stacks the blocks and scrolls; budget a desktop screen.
|
|
12
|
+
|
|
13
|
+
**Do:** A period control, a row of figures, a short list of exceptions.
|
|
14
|
+
|
|
15
|
+
**Don't:** A second screen of blocks below the figures.
|
|
16
|
+
|
|
17
|
+
## Put only figures, trends and exceptions on a dashboard
|
|
18
|
+
|
|
19
|
+
<!-- rule: figures-and-exceptions -->
|
|
20
|
+
|
|
21
|
+
**Rule:** Keep a dashboard to figures, trends and the rows that need attention.
|
|
22
|
+
|
|
23
|
+
**Why:** Reading a table is what a report is for.
|
|
24
|
+
|
|
25
|
+
**Do:** The figures with their trends, then the payouts needing a decision.
|
|
26
|
+
|
|
27
|
+
**Don't:** The whole ledger and a paragraph about it.
|
|
28
|
+
|
|
29
|
+
## Link each reference to its row
|
|
30
|
+
|
|
31
|
+
<!-- rule: link-to-the-report -->
|
|
32
|
+
|
|
33
|
+
**Rule:** Link each reference to its report row and bring that row into view.
|
|
34
|
+
|
|
35
|
+
**Why:** A dashboard stops at what happened; a report opening at its own top has not answered the reference.
|
|
36
|
+
|
|
37
|
+
**Do:** Each payout reference opens its row in the report.
|
|
38
|
+
|
|
39
|
+
**Don't:** A block that lists what is wrong and offers no way in.
|
|
40
|
+
|
|
41
|
+
## Build a report for the whole answer
|
|
42
|
+
|
|
43
|
+
<!-- rule: report-depth -->
|
|
44
|
+
|
|
45
|
+
**Rule:** Answer “why, and exactly how much”, with the rows behind the figure.
|
|
46
|
+
|
|
47
|
+
**Why:** Analysis needs the rows: a summary cannot say how much.
|
|
48
|
+
|
|
49
|
+
**Do:** The payout ledger, with the fees and net on every row.
|
|
50
|
+
|
|
51
|
+
**Don't:** The same ledger reduced to three figures.
|
|
52
|
+
|
|
53
|
+
## Give a report its filters and its export
|
|
54
|
+
|
|
55
|
+
<!-- rule: report-offers -->
|
|
56
|
+
|
|
57
|
+
**Rule:** Offer filters and one export on every report.
|
|
58
|
+
|
|
59
|
+
**Why:** Narrowing the question, or taking the rows away, needs no second screen.
|
|
60
|
+
|
|
61
|
+
**Gap #555:** The kit's Stock screener is a report with filters and no export.
|
|
62
|
+
|
|
63
|
+
**Do:** A filter row above the table, the export at its end.
|
|
64
|
+
|
|
65
|
+
**Don't:** A table alone, its period fixed when it was built.
|
|
66
|
+
|
|
67
|
+
## Put the table under every chart
|
|
68
|
+
|
|
69
|
+
<!-- rule: table-behind-the-chart -->
|
|
70
|
+
|
|
71
|
+
**Rule:** Show the table a chart was drawn from under it, on every report.
|
|
72
|
+
|
|
73
|
+
**Why:** A chart shows the shape of a change, not the amount it is read for.
|
|
74
|
+
|
|
75
|
+
**Do:** The months as bars, then the same months as rows.
|
|
76
|
+
|
|
77
|
+
**Don't:** The bars alone, every month estimated by eye.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**Why:** Without a legend, readers need labels for unfamiliar glyphs.
|
|
10
10
|
|
|
11
|
-
**Except:** [Earn a wordless button](https://ui.apli.tech/storybook/?path=/story/guidelines-button-labels--button-labels)
|
|
11
|
+
**Except:** New entries require a decision and the three tests in [Earn a wordless button](https://ui.apli.tech/storybook/?path=/story/guidelines-button-labels--button-labels). Allowed: close, copy, overflow, expand, collapse and export. Theme toggles, sidebar toggles and collapsed-rail links have separate approval.
|
|
12
12
|
|
|
13
13
|
**Do:** Show an overflow menu without words; keep the Settings label.
|
|
14
14
|
|
package/guidelines/stat-bands.md
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
**Rule:** Put key figures in a stat band, not in a card of parts.
|
|
8
8
|
|
|
9
|
-
**Why:** A shared layout
|
|
9
|
+
**Why:** A shared layout puts every figure's value, change and basis in the same place.
|
|
10
10
|
|
|
11
|
-
**Do:**
|
|
11
|
+
**Do:** One card per figure: the figure largest, an arrow, a signed change, one caption above the row.
|
|
12
12
|
|
|
13
|
-
**Don't:**
|
|
13
|
+
**Don't:** Heading-sized figures, a capitalised 10px status chip, no comparison basis.
|
|
14
14
|
|
|
15
15
|
## Colour by meaning
|
|
16
16
|
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
|
|
21
21
|
**Why:** Direction alone does not show whether a change is beneficial.
|
|
22
22
|
|
|
23
|
-
**Except:** Omitted tone and explicit “neutral” keep the arrow and comparison
|
|
23
|
+
**Except:** Omitted tone and explicit “neutral” keep the arrow and comparison without colour: unscored volume, reader-dependent meaning, net cashflow that income less cost already explains.
|
|
24
24
|
|
|
25
|
-
**Do:**
|
|
25
|
+
**Do:** Four verdicts: rising Income and Cost take opposite colours; falling Unclassified is green; undeclared Net cashflow stays grey.
|
|
26
26
|
|
|
27
|
-
**Don't:**
|
|
27
|
+
**Don't:** Four figures coloured by sign: three rises green, cost growth praised, the year’s cleanup red.
|
|
28
28
|
|
|
29
29
|
## State the comparison basis
|
|
30
30
|
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
|
|
35
35
|
**Why:** Percentages need a basis that readers can find.
|
|
36
36
|
|
|
37
|
-
**
|
|
37
|
+
**Except:** A comparison basis may be screen-reader-only when the visible control names the period. Use this exception for the Finance dashboard pattern.
|
|
38
38
|
|
|
39
|
-
**
|
|
39
|
+
**Do:** The basis once, in a caption each change references or beside one exception; the caption before and outside every figure.
|
|
40
|
+
|
|
41
|
+
**Don't:** A title attribute, the note below the tiles or inside the first figure, no basis, nested captions.
|
package/guidelines/the-page.md
CHANGED
|
@@ -114,10 +114,10 @@
|
|
|
114
114
|
|
|
115
115
|
<!-- rule: lede -->
|
|
116
116
|
|
|
117
|
-
**Rule:**
|
|
117
|
+
**Rule:** A page may open on its title alone; where there is an introduction, keep it to two sentences or fewer and add information the title does not give.
|
|
118
118
|
|
|
119
119
|
**Why:** Repeating the title wastes the reader’s time.
|
|
120
120
|
|
|
121
121
|
**Do:** Below “Payouts”, say “Payouts arrive within three business days.”
|
|
122
122
|
|
|
123
|
-
**Don't:** Write “This is the payouts page” below “Payouts
|
|
123
|
+
**Don't:** Write “This is the payouts page” below “Payouts,” or keep a line there because the page looks bare without one.
|
package/package.json
CHANGED
package/react/dist/index.css
CHANGED
|
@@ -80,6 +80,9 @@
|
|
|
80
80
|
--tap-clear-x: var(--tap-gap);
|
|
81
81
|
--tap-clear-y: var(--tap-gap);
|
|
82
82
|
}
|
|
83
|
+
.ui-toolbar--split .ui-filter-bar {
|
|
84
|
+
column-gap: calc(var(--tap-gap) + var(--space-1) + 1px) !important;
|
|
85
|
+
}
|
|
83
86
|
.ui-filter-bar__chip {
|
|
84
87
|
--tap-clear-x: 0px;
|
|
85
88
|
--tap-clear-y: 0px;
|
package/src/assets/icons.js
CHANGED
|
@@ -175,6 +175,11 @@ export const iconOnlyAllowed = {
|
|
|
175
175
|
moreVertical: 'overflow menu',
|
|
176
176
|
chevronDown: 'expand or collapse',
|
|
177
177
|
chevronUp: 'expand or collapse',
|
|
178
|
+
// Added by Artur's review of the Finance report, #505: a report's export is a
|
|
179
|
+
// standing offer sat next to the filters that narrow it, and the tray-and-arrow
|
|
180
|
+
// is the glyph a reader has already met doing this everywhere else. The entry
|
|
181
|
+
// is the decision — review did not infer it from the glyph looking obvious.
|
|
182
|
+
download: 'export or download the rows',
|
|
178
183
|
};
|
|
179
184
|
|
|
180
185
|
// The word a wordless control's name may open with. The list above says which
|
|
@@ -190,6 +195,11 @@ export const iconOnlyNames = {
|
|
|
190
195
|
moreVertical: ['more'],
|
|
191
196
|
chevronDown: ['expand', 'collapse', 'show', 'hide'],
|
|
192
197
|
chevronUp: ['expand', 'collapse', 'show', 'hide'],
|
|
198
|
+
// The report's export, #505. Export is the word the kit's own call sites open
|
|
199
|
+
// with; download is the reader's other name for the same action, and the glyph
|
|
200
|
+
// depicts it, so a consumer naming it that way is not borrowing the tray for
|
|
201
|
+
// something else.
|
|
202
|
+
download: ['export', 'download'],
|
|
193
203
|
};
|
|
194
204
|
|
|
195
205
|
// What a glyph means when a component picks it for the reader rather than a
|
package/src/components/stat.js
CHANGED
|
@@ -58,11 +58,20 @@ const figure = ({ label = '', value = '', caption = '', delta, trend = '' }, til
|
|
|
58
58
|
// `basis` is the band's caption: what every change is measured against, said
|
|
59
59
|
// once before the list the way a table's <caption> is, in every layout — under
|
|
60
60
|
// a row of tiles it would read as a note on the last card.
|
|
61
|
+
//
|
|
62
|
+
// `basisId` is the other way to answer the same question: the id of a statement
|
|
63
|
+
// the caller has already placed before the figures, which each change points at
|
|
64
|
+
// instead. It is for a band whose basis is stated by something beside it — a
|
|
65
|
+
// period control over a dashboard's figures selects the window every change is
|
|
66
|
+
// measured against, and a caption under it would say that again. React's
|
|
67
|
+
// StatBand has carried it since the period showcase; this is the factory's half.
|
|
68
|
+
// `basis` wins when both are passed, because a band that draws its own caption
|
|
69
|
+
// has said it.
|
|
61
70
|
// why: docs/components.md#stat-bands
|
|
62
|
-
export function statBand({ stats = [], variant = 'tiles', basis = '', label, id } = {}) {
|
|
71
|
+
export function statBand({ stats = [], variant = 'tiles', basis = '', basisId: shared = '', label, id } = {}) {
|
|
63
72
|
const v = STAT_VARIANTS.includes(variant) ? variant : 'tiles';
|
|
64
73
|
const base = id ? esc(id) : `ui-stats-${++seq}`;
|
|
65
|
-
const basisId = basis ? `${base}-basis` : '';
|
|
74
|
+
const basisId = basis ? `${base}-basis` : (shared ? esc(shared) : '');
|
|
66
75
|
const cls = cx('ui-stats', `ui-stats--${v}`, v === 'band' && 'ui-card');
|
|
67
76
|
const named = label ? ` role="group" aria-label="${esc(label)}"` : '';
|
|
68
77
|
const items = stats.map((s) => figure(s, v === 'tiles', basisId)).join('');
|
package/src/styles/card.css
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
.ui-filter-bar { border: 0; padding: 0; margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-width: 0; }
|
|
2
2
|
.ui-filter-bar__legend { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); }
|
|
3
|
-
|
|
3
|
+
/* A chip is a control, so it is painted like the controls beside it: the field
|
|
4
|
+
surface and the same edge a button takes. Left transparent it read as the page
|
|
5
|
+
showing through a switched-off box — the complaint behind #505's review. */
|
|
6
|
+
.ui-filter-bar__chip {
|
|
7
|
+
display: inline-flex; align-items: center; min-width: 0; margin: 0;
|
|
8
|
+
border: 1px solid var(--control-edge); border-radius: var(--radius-sm); padding: var(--space-1);
|
|
9
|
+
/* The chip holds two focus targets of its own — the trigger and the remove
|
|
10
|
+
button — so it is a painted container, not a control that inherits the gap
|
|
11
|
+
outside it. It joins the shared recomposition in tokens.css beside .ui-seg,
|
|
12
|
+
which is also what hands an inline code chip the page from here. */
|
|
13
|
+
background: var(--surface);
|
|
14
|
+
}
|
|
4
15
|
.ui-filter-bar__chip .ui-dropdown__trigger { border: 0; background: transparent; padding: var(--space-1) var(--space-2); }
|
|
5
16
|
.ui-filter-bar__remove { border: 0; background: transparent; color: var(--text); font: inherit; text-align: center; font-size: var(--text-lg); padding: 0; min-width: 24px; min-height: 24px; border-radius: var(--radius-xs); cursor: pointer; }
|
|
6
17
|
.ui-filter-bar__remove:focus-visible,
|
|
7
18
|
.ui-filter-bar:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
8
19
|
.ui-filter-bar button:disabled { /* muted-ink: state — disabled filters */ color: var(--disabled-ink); cursor: not-allowed; }
|
|
9
20
|
|
|
21
|
+
/* The chip's value takes its button's own ink, so a disabled chip keeps the
|
|
22
|
+
disabled ink it inherits instead of the value ink the enabled rules set. */
|
|
10
23
|
.ui-filter-bar .ui-dropdown__value { color: inherit; }
|
|
24
|
+
.ui-filter-bar button:enabled .ui-dropdown__value { color: var(--strong); }
|
|
11
25
|
/* A chip with nothing chosen prints the field's name in the slot the value will
|
|
12
|
-
take
|
|
13
|
-
|
|
26
|
+
take — in the page's reading ink, not --muted. --disabled-ink IS --muted, so a
|
|
27
|
+
muted name on an offered filter said "switched off" in the one ink the kit
|
|
28
|
+
reserves for that; the pick keeps the heavier, darker value ink, so a chosen
|
|
29
|
+
chip and an empty one are still told apart. `:enabled` leaves a disabled chip
|
|
30
|
+
its own ink. why: guidelines/labels-and-titles.md, #505 */
|
|
31
|
+
.ui-filter-bar button:enabled .ui-dropdown__value.is-placeholder { color: var(--text); font-weight: var(--weight-normal); }
|
|
14
32
|
|
|
15
33
|
/* Shut, a panel is the trigger's width, never the 240px floor a standalone
|
|
16
34
|
dropdown gets: it is laid out while hidden, so a wider one widened the page
|
package/src/styles/layout.css
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
resting step. */
|
|
120
120
|
/* Re-tuned at #295, which took the light rail down a step with the page. Below 720px
|
|
121
121
|
the glyph is the whole row, so it is held at text grade rather than at 1.4.11's bar —
|
|
122
|
-
stories/apps/shell-states.test.js:
|
|
122
|
+
stories/apps/shell-states.test.js:1705 `a resting glyph is dimmer but still legible`. */
|
|
123
123
|
.ui-app__rail .ui-nav__ic svg { opacity: 0.66; }
|
|
124
124
|
|
|
125
125
|
/* A destructive row of the rail is a navigation row and rests like one; the danger
|
|
@@ -437,10 +437,9 @@
|
|
|
437
437
|
letter-spacing: var(--tracking-tight);
|
|
438
438
|
margin-bottom: 8px;
|
|
439
439
|
}
|
|
440
|
-
/* The head keeps the kit's second step below it whether or not a lede is there to
|
|
441
|
-
carry it: with no lede the title's own margin takes the step instead. */
|
|
442
|
-
.ui-app__main h1:not(.ui-card h1):not(:has(+ .ui-app__sub)) { margin-bottom: var(--space-8); }
|
|
443
440
|
.ui-app__sub { color: var(--text); font-size: calc(var(--text-base) + 0.5px); line-height: 1.6; max-width: var(--prose-body); margin-bottom: var(--space-8); }
|
|
441
|
+
/* A page may open on its title alone; then the title carries the head's step. */
|
|
442
|
+
.ui-app__main > h1:not(:has(+ .ui-app__sub)) { margin-bottom: var(--space-8); }
|
|
444
443
|
.ui-app__body { display: flex; flex-direction: column; gap: var(--space-5); }
|
|
445
444
|
/* A flex child's min-width is its content by default, so one wide block — a
|
|
446
445
|
ledger, a code sample — pushes the whole page sideways instead of scrolling
|
|
@@ -459,14 +458,48 @@
|
|
|
459
458
|
of what you typed. min-width:0 keeps an input's automatic minimum (its `size`
|
|
460
459
|
attribute, ~20 characters) from setting a floor well above the basis. */
|
|
461
460
|
.ui-toolbar { display: flex; flex-wrap: wrap; gap: 10px; }
|
|
461
|
+
/* A control row belongs to the block it narrows rather than standing beside it,
|
|
462
|
+
so it sits closer than .ui-app__body's gap between two blocks that are each
|
|
463
|
+
their own subject. Not on the last row: there the gap is the page's bottom
|
|
464
|
+
and nothing is being narrowed. why: Artur's review of the Finance report, #505 */
|
|
465
|
+
.ui-app__body > .ui-toolbar:not(:last-child) { margin-bottom: calc(var(--space-3) - var(--space-5)); }
|
|
462
466
|
.ui-toolbar > .ui-input,
|
|
463
467
|
.ui-toolbar > .ui-input-group { flex: 1 1 6rem; min-width: 0; }
|
|
468
|
+
/* A row that offers the block two unrelated things — what to narrow it by, and
|
|
469
|
+
what to do with it — puts the second at the far end instead of beside the
|
|
470
|
+
first. The auto margin is the same one the rail's fold toggle rides to the end
|
|
471
|
+
of the brand row, so the gap between the two groups is whatever the line has
|
|
472
|
+
left and the row still wraps on its own. Above the phone step a wrapped line
|
|
473
|
+
keeps the end it was sent to; below it there is no line, and the rule in the
|
|
474
|
+
query further down takes the margin off.
|
|
475
|
+
why: Artur's review of the Finance report, #505 */
|
|
476
|
+
.ui-toolbar--split > :last-child { margin-inline-start: auto; }
|
|
464
477
|
/* At one column the 6rem basis stops being a floor and becomes the field's size:
|
|
465
478
|
a row with two narrow chips beside it keeps all three on the line and cuts the
|
|
466
479
|
field's own placeholder off. why: docs/components.md#a-toolbar-at-one-column */
|
|
467
480
|
@media (max-width: 560px) {
|
|
468
481
|
.ui-toolbar > .ui-input,
|
|
469
482
|
.ui-toolbar > .ui-input-group { flex-basis: 100%; }
|
|
483
|
+
/* The end control stays IN the row at this width rather than dropping under it.
|
|
484
|
+
A flex line breaks on hypothetical sizes, so a group whose content is wider
|
|
485
|
+
than the line takes that line alone however much it shrinks afterwards: at
|
|
486
|
+
390 the report's filter group asks for about 340px of chips and clear in a
|
|
487
|
+
284px row, so the 36px export went to a line of its own, left-aligned under
|
|
488
|
+
the clear button — which is the reading `--split` exists to prevent, drawn
|
|
489
|
+
vertically. Given a basis the group no longer claims the whole line, the end
|
|
490
|
+
control fits beside it, and the group grows into what is left. 60% rather
|
|
491
|
+
than half because at 560 half still left room for the group beside the
|
|
492
|
+
period strip, which put the export back under the row.
|
|
493
|
+
|
|
494
|
+
The auto margin goes: with the group grown there is no slack for it to take,
|
|
495
|
+
and on the line it did have it left the control against the right edge of an
|
|
496
|
+
otherwise empty row — a mark that came loose rather than what to do with the
|
|
497
|
+
block, which is what Artur marked on round r31. `align-self` is what keeps
|
|
498
|
+
the control its own height beside a group two lines tall; it sits at the
|
|
499
|
+
row's top end, the corner it keeps above this step.
|
|
500
|
+
why: Artur's review of the Finance report, rounds r31 and r34, #505 */
|
|
501
|
+
.ui-toolbar--split > :nth-last-child(2) { flex: 1 1 60%; min-width: 0; }
|
|
502
|
+
.ui-toolbar--split > :last-child { margin-inline-start: 0; align-self: start; }
|
|
470
503
|
}
|
|
471
504
|
|
|
472
505
|
/* -- The narrow rail ------------------------------------------------------ */
|
package/src/styles/stat.css
CHANGED
|
@@ -139,6 +139,20 @@ dd.ui-stat__caption { contain: inline-size; }
|
|
|
139
139
|
@container (width <= 28rem) {
|
|
140
140
|
.ui-stats__list > .ui-stat { flex-basis: 100%; }
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
/* Stacking runs out before a phone does. One figure to a row, a value can still
|
|
144
|
+
be wider than the box holding it — it may neither wrap nor truncate — so the
|
|
145
|
+
band pushed its column sideways: at 320, 15px past the shell's 214px column
|
|
146
|
+
and 19px past a specimen cell. Below its own width the value takes the rank
|
|
147
|
+
under it. A width each, because a tile pads its figure and an open band does
|
|
148
|
+
not, so they stop fitting 16px apart; what a figure longer than the kit's own
|
|
149
|
+
still does is in docs/components.md#stat-bands. #505 */
|
|
150
|
+
@container (width <= 14rem) {
|
|
151
|
+
.ui-stats:not(.ui-stats--open) .ui-stats__list > .ui-stat .ui-stat__value { font-size: var(--text-xl); }
|
|
152
|
+
}
|
|
153
|
+
@container (width <= 15rem) {
|
|
154
|
+
.ui-stats--open .ui-stats__list > .ui-stat .ui-stat__value { font-size: var(--text-2xl); }
|
|
155
|
+
}
|
|
142
156
|
@container (32rem < width <= 66rem) {
|
|
143
157
|
.ui-stats--open .ui-stats__list:has(> .ui-stat:nth-child(4):last-child) > .ui-stat { flex-basis: 34%; }
|
|
144
158
|
}
|
package/src/styles/table.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
2
|
* Table — .ui-table (hairline rows, opaque base surface)
|
|
3
|
-
* Row modifiers: .is-dead (revoked/struck), right-aligned .ui-table__act
|
|
3
|
+
* Row modifiers: .is-dead (revoked/struck), .is-target (landed on), right-aligned .ui-table__act
|
|
4
4
|
* ========================================================================== */
|
|
5
5
|
|
|
6
6
|
.ui-table {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
/* Data-table modifiers, composable: .ui-table--dense --zebra --hover.
|
|
77
77
|
* --dense --space-3 across, --space-2 down — one step in from the base table
|
|
78
78
|
* --zebra legacy spacing and 2px header rule; the base-surface rule below removes stripes
|
|
79
|
-
* Cell helpers: .ui-table__num (right, tabular), .ui-table__code.
|
|
79
|
+
* Cell helpers: .ui-table__num (right, tabular), .ui-table__code, .ui-table__pair.
|
|
80
80
|
* why: docs/foundations.md#spacing-and-rhythm
|
|
81
81
|
* held by: stories/table-rhythm.test.js */
|
|
82
82
|
.ui-table--dense th { padding: 0 var(--space-3) var(--space-2); }
|
|
@@ -116,6 +116,22 @@
|
|
|
116
116
|
color: var(--strong);
|
|
117
117
|
text-decoration: underline;
|
|
118
118
|
}
|
|
119
|
+
/* One exception, and it is the way through: a reference that opens another screen at
|
|
120
|
+
this row. The rule above was written to keep a LEDGER's identifiers out of the accent
|
|
121
|
+
— a whole column of them is an accent with no job (guidelines/density-and-accents.md,
|
|
122
|
+
give-accents-a-job) — but a dashboard's exceptions are three rows, and there the link
|
|
123
|
+
is how a reader reaches the row's own report. Left in the row's ink it was the plain
|
|
124
|
+
cell beside it to the pixel, resolving only on hover, which a phone does not have.
|
|
125
|
+
.ui-table__pair is the cell that carries a reference and its state, so the exception is
|
|
126
|
+
as narrow as that cell. The ink is base.css's own `a { color: var(--accent) }`, at
|
|
127
|
+
7.34:1 in light and 5.53:1 in dark on the table's ground.
|
|
128
|
+
why: Artur, round r34; guidelines/dashboards-and-reports.md#link-each-reference-to-its-row
|
|
129
|
+
held by: src/styles/table.test.js */
|
|
130
|
+
.ui-table :where(td, th) .ui-table__pair a:not(.ui-btn):not(.ui-identity) { color: var(--accent); }
|
|
131
|
+
.ui-table :where(td, th) .ui-table__pair a:not(.ui-btn):not(.ui-identity):hover {
|
|
132
|
+
color: var(--accent);
|
|
133
|
+
text-decoration: underline;
|
|
134
|
+
}
|
|
119
135
|
/* A plain link — one carrying no class — is the link these rules are about. An inline-block
|
|
120
136
|
box, so a title link that wraps paints one ring instead of one per line, and the kit's small
|
|
121
137
|
corner for that ring to follow. Anchors the kit already styles (`.ui-btn`, `.ui-identity`,
|
|
@@ -163,6 +179,15 @@
|
|
|
163
179
|
* row reads as one row. */
|
|
164
180
|
.ui-table :is(th, td).ui-table__num--strong { color: var(--strong); font-weight: var(--weight-semibold); }
|
|
165
181
|
.ui-table__code { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text); }
|
|
182
|
+
/* Two things in one cell — a row's own name and the state of it — side by side
|
|
183
|
+
* while the column has room and stacked when it does not. The wrap comes from flex
|
|
184
|
+
* because a dense cell is nowrap, and the column is then only as wide as the wider
|
|
185
|
+
* of the two: a status that had a column of its own was the first thing a phone cut
|
|
186
|
+
* off, and in here it is the last. The class goes on a span inside the cell, never
|
|
187
|
+
* on the cell, which would leave the table box model. A row carrying a paragraph takes
|
|
188
|
+
* .ui-table--stack below instead, which drops the head; a pair keeps every head at every
|
|
189
|
+
* width, which is what a three-value glance row is read by. why: #505 */
|
|
190
|
+
.ui-table__pair { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
|
|
166
191
|
|
|
167
192
|
/* The empty state (.ui-empty) — shown when a table/list has no rows — now
|
|
168
193
|
lives in styles/empty.css as a standalone component (illustration support). */
|
|
@@ -182,6 +207,41 @@
|
|
|
182
207
|
}
|
|
183
208
|
.ui-table tbody tr:hover { outline: 1px solid var(--border-strong); outline-offset: -1px; }
|
|
184
209
|
|
|
210
|
+
/* The row a reference landed a reader on. The mark is a GROUND, not a line: an outline
|
|
211
|
+
says the keyboard is here (Artur, r34), and this one persists — it answers which row the
|
|
212
|
+
reader came for, so it stays until the next arrival and must not wear the picture focus
|
|
213
|
+
draws. It took --ring-scroll until #505's review found a landed row still outlined in the
|
|
214
|
+
accent after focus had moved on, with a second row beside it wearing the same box.
|
|
215
|
+
The ground and the ring paint together on arrival: `landOnRow()` focuses the row, so a
|
|
216
|
+
reader must see both at once, not the ring now and the ground only after they tab away.
|
|
217
|
+
|
|
218
|
+
The wash is the accent over the table's own ground: the family `tbody tr:hover` already
|
|
219
|
+
uses for "this row", one step up from its 8% so the two are told apart. 12% is the
|
|
220
|
+
strongest step that keeps an accent link inside the row above 4.5:1 — 4.60:1 at the worst
|
|
221
|
+
of the eight accent/theme cells, against 4.45:1 at 14%. It paints cells rather than the
|
|
222
|
+
row, because the hover and zebra rules paint cells and would otherwise cover it; the two
|
|
223
|
+
hover selectors are repeated with .is-target so a pointer passing over the row does not
|
|
224
|
+
take its mark off.
|
|
225
|
+
why: Artur, round r34; guidelines/dashboards-and-reports.md#link-each-reference-to-its-row
|
|
226
|
+
held by: stories/dashboard-report-refs.test.js, for landOnRow() marking the right row and
|
|
227
|
+
only the right row; stories/contrast.test.js, for the wash's contrast, now that
|
|
228
|
+
stories/components/Table.stories.js:FinanceData renders a row wearing the mark at rest.
|
|
229
|
+
Neither gate reads paint against focus: the ground and the ring share no selector and no
|
|
230
|
+
condition, which is why one cannot switch the other off, and that is proved by the PR's
|
|
231
|
+
browser captures rather than by a gate. PR #552 code review, finding F6. */
|
|
232
|
+
.ui-table tbody tr.is-target > :is(td, th),
|
|
233
|
+
.ui-table--hover tbody tr.is-target:hover > :is(td, th),
|
|
234
|
+
.ui-table--zebra.ui-table--hover tbody tr.is-target:hover > :is(td, th) {
|
|
235
|
+
background: color-mix(in srgb, var(--accent) 12%, transparent); /* code-bg: inherit — this translucent wash leaves the chip on its opaque ground. */
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* A focused row draws the shared ring inward, like its containing scroll region.
|
|
239
|
+
why: docs/foundations.md#the-focus-ring */
|
|
240
|
+
.ui-table tbody tr:focus-visible {
|
|
241
|
+
outline: var(--ring-scroll);
|
|
242
|
+
outline-offset: var(--ring-scroll-offset);
|
|
243
|
+
}
|
|
244
|
+
|
|
185
245
|
/* The end-cell inset above gives a row's highlight room; the bleed is what stops the grid
|
|
186
246
|
paying for it. The table hangs out by the same --space-3, into the card's 20-24px
|
|
187
247
|
padding and never past it, so the columns start on the card's own text edge and the
|
package/src/styles/tap-zone.css
CHANGED
|
@@ -140,6 +140,9 @@
|
|
|
140
140
|
/* Chips open both ways: the row wraps, and the button at the end of it is a
|
|
141
141
|
target like the chips are. */
|
|
142
142
|
.ui-filter-bar { gap: var(--tap-gap) !important; --tap-clear-x: var(--tap-gap); --tap-clear-y: var(--tap-gap); }
|
|
143
|
+
/* In a split toolbar the rail row beside the report sits on the same line as
|
|
144
|
+
Clear all. One step plus 1px keeps the button's layer off that row. */
|
|
145
|
+
.ui-toolbar--split .ui-filter-bar { column-gap: calc(var(--tap-gap) + var(--space-1) + 1px) !important; }
|
|
143
146
|
|
|
144
147
|
/* Inside a chip there is nothing to open: parting the value from its remove
|
|
145
148
|
mark would draw two controls where the reader sees one. Named on the
|