@axiapps/axi-design 1.28.0 → 1.30.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 +4 -0
- package/dist/axi.css +59 -13
- package/docs/RULES.md +21 -6
- package/package.json +1 -1
- package/src/primitives.css +58 -12
- package/src/shells.css +1 -1
package/README.md
CHANGED
|
@@ -138,6 +138,10 @@ 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">` |
|
|
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">` |
|
|
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">` |
|
|
141
145
|
| `--axi-well-pad` | the padding inside an `.axi-well` | `10px` | `<div class="axi-well" style="--axi-well-pad: 18px">` |
|
|
142
146
|
| `--axi-well-radius` | an `.axi-well`'s corner radius, for a well used at reading scale rather than page scale | `var(--axi-radius)` | `<div class="axi-well" style="--axi-well-radius: var(--axi-radius-sm)">` |
|
|
143
147
|
| `--axi-rail-w` | an `.axi-rail`'s width, for labels longer than the default holds | `208px` | `<aside class="axi-rail" style="--axi-rail-w: 260px">` |
|
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);
|
|
@@ -562,15 +600,23 @@ button.axi-panel--tile:hover,
|
|
|
562
600
|
.axi-diamond--series { background: var(--axi-series, var(--axi-accent)); }
|
|
563
601
|
|
|
564
602
|
/* ---------- input ---------- */
|
|
603
|
+
/* Two knobs rather than one fixed size, for the same reason --axi-well-pad
|
|
604
|
+
exists: a field is used at two scales. A form control standing on a page is
|
|
605
|
+
the 14px default; a filter sitting in a section header or a row in a bar is
|
|
606
|
+
smaller, because there it is furniture next to 11px type rather than the
|
|
607
|
+
thing the page is for. The alternative is what this file did before - a
|
|
608
|
+
context selector per place that wanted the small one (.axi-palette__bar
|
|
609
|
+
.axi-input, still the only one upstream needs) - and that does not scale
|
|
610
|
+
past the cases upstream happens to ship. */
|
|
565
611
|
.axi-input {
|
|
566
612
|
width: 100%;
|
|
567
|
-
padding: 11px 12px;
|
|
613
|
+
padding: var(--axi-input-pad, 11px 12px);
|
|
568
614
|
background: var(--axi-ground);
|
|
569
615
|
border: var(--axi-border-control) solid var(--axi-ink-line);
|
|
570
616
|
border-radius: var(--axi-radius-sm);
|
|
571
617
|
color: var(--axi-text);
|
|
572
618
|
font: var(--axi-t-label);
|
|
573
|
-
font-size: 14px;
|
|
619
|
+
font-size: var(--axi-input-size, 14px);
|
|
574
620
|
}
|
|
575
621
|
.axi-input::placeholder { color: var(--axi-text-faint); font-weight: 500; }
|
|
576
622
|
|
|
@@ -1411,7 +1457,7 @@ textarea.axi-input {
|
|
|
1411
1457
|
not a form control standing on a page. No focus ring: the palette opens with
|
|
1412
1458
|
the caret already here, so a permanent outline says nothing, and it would
|
|
1413
1459
|
argue with the one mark that does - the accent on the cursor row. */
|
|
1414
|
-
.axi-palette__bar .axi-input {
|
|
1460
|
+
.axi-palette__bar .axi-input { --axi-input-pad: 7px 12px; --axi-input-size: 13px; }
|
|
1415
1461
|
.axi-palette__bar .axi-input:focus-visible { outline: none; }
|
|
1416
1462
|
.axi-palette__filters { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
|
|
1417
1463
|
/* What the list is not showing. Meta, at the end of the filter row, because it
|
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);
|
|
@@ -288,15 +326,23 @@ button.axi-panel--tile:hover,
|
|
|
288
326
|
.axi-diamond--series { background: var(--axi-series, var(--axi-accent)); }
|
|
289
327
|
|
|
290
328
|
/* ---------- input ---------- */
|
|
329
|
+
/* Two knobs rather than one fixed size, for the same reason --axi-well-pad
|
|
330
|
+
exists: a field is used at two scales. A form control standing on a page is
|
|
331
|
+
the 14px default; a filter sitting in a section header or a row in a bar is
|
|
332
|
+
smaller, because there it is furniture next to 11px type rather than the
|
|
333
|
+
thing the page is for. The alternative is what this file did before - a
|
|
334
|
+
context selector per place that wanted the small one (.axi-palette__bar
|
|
335
|
+
.axi-input, still the only one upstream needs) - and that does not scale
|
|
336
|
+
past the cases upstream happens to ship. */
|
|
291
337
|
.axi-input {
|
|
292
338
|
width: 100%;
|
|
293
|
-
padding: 11px 12px;
|
|
339
|
+
padding: var(--axi-input-pad, 11px 12px);
|
|
294
340
|
background: var(--axi-ground);
|
|
295
341
|
border: var(--axi-border-control) solid var(--axi-ink-line);
|
|
296
342
|
border-radius: var(--axi-radius-sm);
|
|
297
343
|
color: var(--axi-text);
|
|
298
344
|
font: var(--axi-t-label);
|
|
299
|
-
font-size: 14px;
|
|
345
|
+
font-size: var(--axi-input-size, 14px);
|
|
300
346
|
}
|
|
301
347
|
.axi-input::placeholder { color: var(--axi-text-faint); font-weight: 500; }
|
|
302
348
|
|
package/src/shells.css
CHANGED
|
@@ -439,7 +439,7 @@
|
|
|
439
439
|
not a form control standing on a page. No focus ring: the palette opens with
|
|
440
440
|
the caret already here, so a permanent outline says nothing, and it would
|
|
441
441
|
argue with the one mark that does - the accent on the cursor row. */
|
|
442
|
-
.axi-palette__bar .axi-input {
|
|
442
|
+
.axi-palette__bar .axi-input { --axi-input-pad: 7px 12px; --axi-input-size: 13px; }
|
|
443
443
|
.axi-palette__bar .axi-input:focus-visible { outline: none; }
|
|
444
444
|
.axi-palette__filters { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
|
|
445
445
|
/* What the list is not showing. Meta, at the end of the filter row, because it
|