@axiapps/axi-design 1.29.0 → 1.30.1
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 +2 -0
- package/dist/axi.css +59 -10
- package/docs/RULES.md +21 -6
- package/package.json +1 -1
- package/src/primitives.css +59 -10
package/README.md
CHANGED
|
@@ -138,6 +138,8 @@ not "what does the system look like". Everything else is
|
|
|
138
138
|
| `--axi-check-size` | the size of an `.axi-check` or `.axi-radio` box | `22px` | `<input type="checkbox" class="axi-check" style="--axi-check-size: 16px">` |
|
|
139
139
|
| `--axi-check-fill` | the fill a checked `.axi-check` takes, and the colour of a checked `.axi-radio`'s diamond | `var(--axi-accent)` | `<input type="checkbox" class="axi-check" style="--axi-check-fill: var(--axi-danger)">` |
|
|
140
140
|
| `--axi-textarea-h` | the minimum height of a `<textarea class="axi-input">` | `90px` | `<textarea class="axi-input" style="--axi-textarea-h: 200px">` |
|
|
141
|
+
| `--axi-btn-pad` | the padding inside an `.axi-btn`. The three named steps set it for you; reach for the knob only for a size they do not cover | `12px 20px` | `<button class="axi-btn" style="--axi-btn-pad: 3px 7px">` |
|
|
142
|
+
| `--axi-btn-size` | an `.axi-btn`'s text size, which travels with its padding | `13px` | `<button class="axi-btn" style="--axi-btn-size: 10px">` |
|
|
141
143
|
| `--axi-input-pad` | the padding inside an `.axi-input`, for a field that is furniture in a header rather than a control on a page | `11px 12px` | `<input class="axi-input" style="--axi-input-pad: 7px 12px">` |
|
|
142
144
|
| `--axi-input-size` | an `.axi-input`'s text size, which travels with its padding | `14px` | `<input class="axi-input" style="--axi-input-size: 13px">` |
|
|
143
145
|
| `--axi-well-pad` | the padding inside an `.axi-well` | `10px` | `<div class="axi-well" style="--axi-well-pad: 18px">` |
|
package/dist/axi.css
CHANGED
|
@@ -374,13 +374,15 @@ button.axi-panel--tile:hover,
|
|
|
374
374
|
/* ---------- button ---------- */
|
|
375
375
|
.axi-btn {
|
|
376
376
|
display: inline-flex; align-items: center; gap: 8px;
|
|
377
|
-
padding: 12px 20px;
|
|
377
|
+
padding: var(--axi-btn-pad, 12px 20px);
|
|
378
378
|
border: var(--axi-border-control) solid var(--axi-ink-line);
|
|
379
379
|
border-radius: var(--axi-radius-sm);
|
|
380
380
|
background: var(--axi-ground);
|
|
381
381
|
color: var(--axi-text-dim);
|
|
382
382
|
font: var(--axi-t-label);
|
|
383
383
|
letter-spacing: var(--axi-ls-label);
|
|
384
|
+
/* After the `font` shorthand, which sets 13px and would otherwise reset it. */
|
|
385
|
+
font-size: var(--axi-btn-size, 13px);
|
|
384
386
|
text-transform: uppercase;
|
|
385
387
|
text-decoration: none;
|
|
386
388
|
cursor: pointer;
|
|
@@ -388,8 +390,18 @@ button.axi-panel--tile:hover,
|
|
|
388
390
|
}
|
|
389
391
|
/* Hover lifts. Nothing in this language fades or glows: the block deepens and
|
|
390
392
|
the element moves against it, which reads instantly even in peripheral
|
|
391
|
-
vision and costs no colour.
|
|
392
|
-
|
|
393
|
+
vision and costs no colour.
|
|
394
|
+
|
|
395
|
+
:where() around the state, not decoration. `.axi-btn:hover` weighs two
|
|
396
|
+
classes, so it beat the ink layer's one and a button written
|
|
397
|
+
`class="axi-btn axi-ink-danger"` went from danger red to plain white under
|
|
398
|
+
the cursor - the verdict disappearing at the moment the reader reaches for
|
|
399
|
+
it. That is rule 6's "a component may not out-rank its own modifiers" with
|
|
400
|
+
a pseudo-class doing the out-ranking instead of an element, and it wants the
|
|
401
|
+
same fix. The dim-to-plain brighten still happens: it is the fallback now,
|
|
402
|
+
not an override, so it applies to exactly the buttons that have not been
|
|
403
|
+
told what colour they are. */
|
|
404
|
+
.axi-btn:where(:hover) {
|
|
393
405
|
color: var(--axi-text);
|
|
394
406
|
box-shadow: var(--axi-shadow-control);
|
|
395
407
|
transform: translate(-2px, -2px);
|
|
@@ -402,13 +414,33 @@ button.axi-panel--tile:hover,
|
|
|
402
414
|
/* The one button that rests with a block already under it, so the generic
|
|
403
415
|
hover's translate alone would move element and block together and leave the
|
|
404
416
|
lower-right edge where it started - the "grows rather than lifts" failure
|
|
405
|
-
rule 4 warns about. It lifts the way a panel does: the block deepens too.
|
|
417
|
+
rule 4 warns about. It lifts the way a panel does: the block deepens too.
|
|
418
|
+
|
|
419
|
+
Not wrapped in :where() the way the generic hover is: this colour is the
|
|
420
|
+
accent fill's contrast pair, not a default a consumer might mean to replace.
|
|
421
|
+
An ink reaching it would put a status colour on top of the accent block and
|
|
422
|
+
the label would stop being legible, which is rule 5's reason for the chip. */
|
|
406
423
|
.axi-btn--primary:hover {
|
|
407
424
|
color: var(--axi-accent-ink);
|
|
408
425
|
box-shadow: var(--axi-shadow-control-hover);
|
|
409
426
|
}
|
|
410
427
|
.axi-btn--ghost { background: transparent; }
|
|
411
428
|
.axi-btn--dashed { background: transparent; border-style: dashed; }
|
|
429
|
+
/* Three sizes, because one was a fiction. A language that ships a single
|
|
430
|
+
button leaves every dense place in an app - a filter beside 11px type, a
|
|
431
|
+
toolbar, a row of controls in a card header - to spell its own padding and
|
|
432
|
+
font-size in utilities, and at that point the button is only borrowing the
|
|
433
|
+
border. The steps are named rather than left to the knobs for the same
|
|
434
|
+
reason .axi-table--dense is: a consumer saying "this is the small one"
|
|
435
|
+
should not have to pick the numbers, and the numbers should move together
|
|
436
|
+
when they move.
|
|
437
|
+
The icon step is the one the language got wrong rather than omitted. An
|
|
438
|
+
icon-only button has no label to pad around, so the 20px sides meant for
|
|
439
|
+
one produced a wide rectangle around a single glyph - visible in this
|
|
440
|
+
language's own gallery, in the example titled "Alone in a button". */
|
|
441
|
+
.axi-btn--sm { --axi-btn-pad: 8px 13px; --axi-btn-size: 12px; }
|
|
442
|
+
.axi-btn--xs { --axi-btn-pad: 5px 9px; --axi-btn-size: 11px; }
|
|
443
|
+
.axi-btn--icon { --axi-btn-pad: 7px; }
|
|
412
444
|
|
|
413
445
|
/* ---------- pill ---------- */
|
|
414
446
|
/* A filter toggle. Its pressed state fills with whatever colour the consumer
|
|
@@ -429,7 +461,10 @@ button.axi-panel--tile:hover,
|
|
|
429
461
|
cursor: pointer;
|
|
430
462
|
transition: transform .1s, box-shadow .1s;
|
|
431
463
|
}
|
|
432
|
-
|
|
464
|
+
/* :where() for the same reason the button's hover has it - the brighten is
|
|
465
|
+
what a pill that has not been told its colour falls back to, not an override
|
|
466
|
+
of one that has. See rule 6's addendum. */
|
|
467
|
+
.axi-pill:where(:hover) {
|
|
433
468
|
color: var(--axi-text);
|
|
434
469
|
box-shadow: var(--axi-shadow-control);
|
|
435
470
|
transform: translate(-2px, -2px);
|
|
@@ -439,11 +474,14 @@ button.axi-panel--tile:hover,
|
|
|
439
474
|
color: var(--axi-accent-ink);
|
|
440
475
|
box-shadow: var(--axi-shadow-control);
|
|
441
476
|
}
|
|
442
|
-
/* Spelled out rather than left to
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
477
|
+
/* Spelled out rather than left to the cascade. This was originally about equal
|
|
478
|
+
specificity - the two rules weighed the same, so which one a pressed pill
|
|
479
|
+
under the cursor took was decided by file order. The hover's :where() ended
|
|
480
|
+
the tie in the pressed rule's favour, and made this rule matter more rather
|
|
481
|
+
than less: `transform` is set only by the hover, so a pressed pill would take
|
|
482
|
+
its own fill and block from the higher-weight rule while still taking the
|
|
483
|
+
hover's translate - a slide, not a lift, which is the failure rule 4 names.
|
|
484
|
+
A pressed pill keeps its fill and lifts. */
|
|
447
485
|
.axi-pill[aria-pressed="true"]:hover {
|
|
448
486
|
background: var(--axi-pill-fill, var(--axi-accent));
|
|
449
487
|
color: var(--axi-accent-ink);
|
|
@@ -540,6 +578,17 @@ button.axi-panel--tile:hover,
|
|
|
540
578
|
color: var(--axi-accent-ink);
|
|
541
579
|
font: var(--axi-t-micro);
|
|
542
580
|
}
|
|
581
|
+
/* The one placement where the badge's own fill is the fill it is sitting on.
|
|
582
|
+
.axi-btn--primary is the accent, and so is the badge, so the count went
|
|
583
|
+
invisible - not dim, gone. Inverted rather than given a third colour: the
|
|
584
|
+
same two values the other way round is the only pairing rule 5 leaves, since
|
|
585
|
+
a status hue here would say something about the count that is not true.
|
|
586
|
+
Found by a consumer, which had written this rule itself against its own
|
|
587
|
+
class name because the language had no answer. */
|
|
588
|
+
.axi-btn--primary .axi-badge-count {
|
|
589
|
+
background: var(--axi-accent-ink);
|
|
590
|
+
color: var(--axi-accent);
|
|
591
|
+
}
|
|
543
592
|
|
|
544
593
|
/* ---------- diamond ---------- */
|
|
545
594
|
/* The family motif: a rotated outlined square. Used as a bullet, a status dot
|
package/docs/RULES.md
CHANGED
|
@@ -260,12 +260,27 @@ there is no object, only a mark.
|
|
|
260
260
|
|
|
261
261
|
They live in `src/utilities.css`, last in the cascade, which is how a single
|
|
262
262
|
class overrules the component it sits inside without `!important`. That places
|
|
263
|
-
an obligation on components in the other direction: **a component's base
|
|
264
|
-
may not out-rank its own modifiers.** A rule written `.axi-table td`
|
|
265
|
-
class and a type, so it silently defeats both `.axi-table__num` and any
|
|
266
|
-
consumer puts on the cell — the fix is `:where()` around the element,
|
|
267
|
-
spends no specificity. Where a component holds a consumer's content, wrap
|
|
268
|
-
element part.
|
|
263
|
+
an obligation on components in the other direction: **a component's base and
|
|
264
|
+
state rules may not out-rank its own modifiers.** A rule written `.axi-table td`
|
|
265
|
+
weighs a class and a type, so it silently defeats both `.axi-table__num` and any
|
|
266
|
+
ink a consumer puts on the cell — the fix is `:where()` around the element,
|
|
267
|
+
which spends no specificity. Where a component holds a consumer's content, wrap
|
|
268
|
+
the element part.
|
|
269
|
+
|
|
270
|
+
A pseudo-class does the same arithmetic. `.axi-btn:hover` weighs two classes, so
|
|
271
|
+
a button written `class="axi-btn axi-ink-danger"` was danger red at rest and
|
|
272
|
+
plain white under the cursor: the verdict vanishing at the moment the reader
|
|
273
|
+
reaches for it. Where a state rule restates a colour the consumer might have
|
|
274
|
+
meant to set — a generic control's hover brighten, which applies to whatever has
|
|
275
|
+
not been told what it is — wrap the state: `.axi-btn:where(:hover)`. The
|
|
276
|
+
brighten becomes the fallback it always was.
|
|
277
|
+
|
|
278
|
+
Two things this does not apply to. A colour that *is* the state's meaning stays
|
|
279
|
+
at full weight, because there is nothing for an ink to add and an ink reaching it
|
|
280
|
+
would be wrong: a selected rail item, a palette's cursor row, a pressed pill. And
|
|
281
|
+
a colour that is a fill's contrast pair — `.axi-btn--primary`'s accent ink — stays
|
|
282
|
+
too, because an ink there would put a status colour on the accent block and cost
|
|
283
|
+
the label its legibility, which is rule 5's reason for the chip.
|
|
269
284
|
|
|
270
285
|
## 7. The diamond is the family motif
|
|
271
286
|
|
package/package.json
CHANGED
package/src/primitives.css
CHANGED
|
@@ -100,13 +100,15 @@ button.axi-panel--tile:hover,
|
|
|
100
100
|
/* ---------- button ---------- */
|
|
101
101
|
.axi-btn {
|
|
102
102
|
display: inline-flex; align-items: center; gap: 8px;
|
|
103
|
-
padding: 12px 20px;
|
|
103
|
+
padding: var(--axi-btn-pad, 12px 20px);
|
|
104
104
|
border: var(--axi-border-control) solid var(--axi-ink-line);
|
|
105
105
|
border-radius: var(--axi-radius-sm);
|
|
106
106
|
background: var(--axi-ground);
|
|
107
107
|
color: var(--axi-text-dim);
|
|
108
108
|
font: var(--axi-t-label);
|
|
109
109
|
letter-spacing: var(--axi-ls-label);
|
|
110
|
+
/* After the `font` shorthand, which sets 13px and would otherwise reset it. */
|
|
111
|
+
font-size: var(--axi-btn-size, 13px);
|
|
110
112
|
text-transform: uppercase;
|
|
111
113
|
text-decoration: none;
|
|
112
114
|
cursor: pointer;
|
|
@@ -114,8 +116,18 @@ button.axi-panel--tile:hover,
|
|
|
114
116
|
}
|
|
115
117
|
/* Hover lifts. Nothing in this language fades or glows: the block deepens and
|
|
116
118
|
the element moves against it, which reads instantly even in peripheral
|
|
117
|
-
vision and costs no colour.
|
|
118
|
-
|
|
119
|
+
vision and costs no colour.
|
|
120
|
+
|
|
121
|
+
:where() around the state, not decoration. `.axi-btn:hover` weighs two
|
|
122
|
+
classes, so it beat the ink layer's one and a button written
|
|
123
|
+
`class="axi-btn axi-ink-danger"` went from danger red to plain white under
|
|
124
|
+
the cursor - the verdict disappearing at the moment the reader reaches for
|
|
125
|
+
it. That is rule 6's "a component may not out-rank its own modifiers" with
|
|
126
|
+
a pseudo-class doing the out-ranking instead of an element, and it wants the
|
|
127
|
+
same fix. The dim-to-plain brighten still happens: it is the fallback now,
|
|
128
|
+
not an override, so it applies to exactly the buttons that have not been
|
|
129
|
+
told what colour they are. */
|
|
130
|
+
.axi-btn:where(:hover) {
|
|
119
131
|
color: var(--axi-text);
|
|
120
132
|
box-shadow: var(--axi-shadow-control);
|
|
121
133
|
transform: translate(-2px, -2px);
|
|
@@ -128,13 +140,33 @@ button.axi-panel--tile:hover,
|
|
|
128
140
|
/* The one button that rests with a block already under it, so the generic
|
|
129
141
|
hover's translate alone would move element and block together and leave the
|
|
130
142
|
lower-right edge where it started - the "grows rather than lifts" failure
|
|
131
|
-
rule 4 warns about. It lifts the way a panel does: the block deepens too.
|
|
143
|
+
rule 4 warns about. It lifts the way a panel does: the block deepens too.
|
|
144
|
+
|
|
145
|
+
Not wrapped in :where() the way the generic hover is: this colour is the
|
|
146
|
+
accent fill's contrast pair, not a default a consumer might mean to replace.
|
|
147
|
+
An ink reaching it would put a status colour on top of the accent block and
|
|
148
|
+
the label would stop being legible, which is rule 5's reason for the chip. */
|
|
132
149
|
.axi-btn--primary:hover {
|
|
133
150
|
color: var(--axi-accent-ink);
|
|
134
151
|
box-shadow: var(--axi-shadow-control-hover);
|
|
135
152
|
}
|
|
136
153
|
.axi-btn--ghost { background: transparent; }
|
|
137
154
|
.axi-btn--dashed { background: transparent; border-style: dashed; }
|
|
155
|
+
/* Three sizes, because one was a fiction. A language that ships a single
|
|
156
|
+
button leaves every dense place in an app - a filter beside 11px type, a
|
|
157
|
+
toolbar, a row of controls in a card header - to spell its own padding and
|
|
158
|
+
font-size in utilities, and at that point the button is only borrowing the
|
|
159
|
+
border. The steps are named rather than left to the knobs for the same
|
|
160
|
+
reason .axi-table--dense is: a consumer saying "this is the small one"
|
|
161
|
+
should not have to pick the numbers, and the numbers should move together
|
|
162
|
+
when they move.
|
|
163
|
+
The icon step is the one the language got wrong rather than omitted. An
|
|
164
|
+
icon-only button has no label to pad around, so the 20px sides meant for
|
|
165
|
+
one produced a wide rectangle around a single glyph - visible in this
|
|
166
|
+
language's own gallery, in the example titled "Alone in a button". */
|
|
167
|
+
.axi-btn--sm { --axi-btn-pad: 8px 13px; --axi-btn-size: 12px; }
|
|
168
|
+
.axi-btn--xs { --axi-btn-pad: 5px 9px; --axi-btn-size: 11px; }
|
|
169
|
+
.axi-btn--icon { --axi-btn-pad: 7px; }
|
|
138
170
|
|
|
139
171
|
/* ---------- pill ---------- */
|
|
140
172
|
/* A filter toggle. Its pressed state fills with whatever colour the consumer
|
|
@@ -155,7 +187,10 @@ button.axi-panel--tile:hover,
|
|
|
155
187
|
cursor: pointer;
|
|
156
188
|
transition: transform .1s, box-shadow .1s;
|
|
157
189
|
}
|
|
158
|
-
|
|
190
|
+
/* :where() for the same reason the button's hover has it - the brighten is
|
|
191
|
+
what a pill that has not been told its colour falls back to, not an override
|
|
192
|
+
of one that has. See rule 6's addendum. */
|
|
193
|
+
.axi-pill:where(:hover) {
|
|
159
194
|
color: var(--axi-text);
|
|
160
195
|
box-shadow: var(--axi-shadow-control);
|
|
161
196
|
transform: translate(-2px, -2px);
|
|
@@ -165,11 +200,14 @@ button.axi-panel--tile:hover,
|
|
|
165
200
|
color: var(--axi-accent-ink);
|
|
166
201
|
box-shadow: var(--axi-shadow-control);
|
|
167
202
|
}
|
|
168
|
-
/* Spelled out rather than left to
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
/* Spelled out rather than left to the cascade. This was originally about equal
|
|
204
|
+
specificity - the two rules weighed the same, so which one a pressed pill
|
|
205
|
+
under the cursor took was decided by file order. The hover's :where() ended
|
|
206
|
+
the tie in the pressed rule's favour, and made this rule matter more rather
|
|
207
|
+
than less: `transform` is set only by the hover, so a pressed pill would take
|
|
208
|
+
its own fill and block from the higher-weight rule while still taking the
|
|
209
|
+
hover's translate - a slide, not a lift, which is the failure rule 4 names.
|
|
210
|
+
A pressed pill keeps its fill and lifts. */
|
|
173
211
|
.axi-pill[aria-pressed="true"]:hover {
|
|
174
212
|
background: var(--axi-pill-fill, var(--axi-accent));
|
|
175
213
|
color: var(--axi-accent-ink);
|
|
@@ -266,6 +304,17 @@ button.axi-panel--tile:hover,
|
|
|
266
304
|
color: var(--axi-accent-ink);
|
|
267
305
|
font: var(--axi-t-micro);
|
|
268
306
|
}
|
|
307
|
+
/* The one placement where the badge's own fill is the fill it is sitting on.
|
|
308
|
+
.axi-btn--primary is the accent, and so is the badge, so the count went
|
|
309
|
+
invisible - not dim, gone. Inverted rather than given a third colour: the
|
|
310
|
+
same two values the other way round is the only pairing rule 5 leaves, since
|
|
311
|
+
a status hue here would say something about the count that is not true.
|
|
312
|
+
Found by a consumer, which had written this rule itself against its own
|
|
313
|
+
class name because the language had no answer. */
|
|
314
|
+
.axi-btn--primary .axi-badge-count {
|
|
315
|
+
background: var(--axi-accent-ink);
|
|
316
|
+
color: var(--axi-accent);
|
|
317
|
+
}
|
|
269
318
|
|
|
270
319
|
/* ---------- diamond ---------- */
|
|
271
320
|
/* The family motif: a rotated outlined square. Used as a bullet, a status dot
|