@axiapps/axi-design 1.18.0 → 1.20.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/dist/axi.css CHANGED
@@ -144,6 +144,14 @@
144
144
  control-sized reads --axi-radius-sm. */
145
145
  --axi-radius: 0;
146
146
  --axi-radius-sm: 0;
147
+ /* The third step, for a box the size of the text beside it: a checkbox, a
148
+ radio. --axi-radius-sm is sized for something you press - a button, an
149
+ input, 36px tall - and a theme is free to set it to 10px. On a 22px
150
+ square 10px is most of the box: the checkbox stops being a square and
151
+ becomes a circle, and a circle next to rule 7's diamond radio is the one
152
+ shape confusion this pair exists to avoid. A theme that wants soft
153
+ corners sets all three. */
154
+ --axi-radius-xs: 0;
147
155
  /* Not a form step: a hairline used inside prose (inline code, table rules,
148
156
  the list bullet) where the two form steps above would read as too heavy
149
157
  for a line of running text. */
@@ -286,6 +294,15 @@ a { color: inherit; }
286
294
  fit is genuinely called for. */
287
295
  padding: var(--axi-panel-pad, 26px);
288
296
  }
297
+ /* A panel that floats over moving content rather than sitting in the page: a
298
+ readout pinned to a chart, a popover over a scrolling table. Same object,
299
+ same everything else; the one thing that changes is the surface it is
300
+ printed on. --axi-surface is a translucent tint under a theme like glass,
301
+ which reads as a pane only while what is behind it holds still - the moment
302
+ the content scrolls, it shows through the panel. --axi-surface-float is the
303
+ surface for exactly that case. Says the same thing .axi-rail--float says,
304
+ on the other surface that needs it. */
305
+ .axi-panel--float { background: var(--axi-surface-float); }
289
306
 
290
307
  /* ---------- well ---------- */
291
308
  /* The panel's inverse: a field sunk into the surface around it rather than
@@ -795,7 +812,10 @@ a { color: inherit; }
795
812
  place-items: center;
796
813
  background: var(--axi-ground);
797
814
  border: var(--axi-border-control) solid var(--axi-ink-line);
798
- border-radius: var(--axi-radius-sm);
815
+ /* The text-sized step, not the control-sized one - see --axi-radius-xs in
816
+ src/tokens.css for why a 22px box cannot take a corner scaled for a 36px
817
+ button. */
818
+ border-radius: var(--axi-radius-xs);
799
819
  cursor: pointer;
800
820
  }
801
821
  /* The mark is always in the DOM and revealed with opacity rather than being
@@ -922,6 +942,29 @@ textarea.axi-input {
922
942
  padding-inline: var(--axi-gutter);
923
943
  display: flex; align-items: center; gap: 22px; min-height: 66px; flex-wrap: wrap;
924
944
  }
945
+ /* Above --axi-page the row stops growing: the cap is on this box, not on the
946
+ window, so from 1280px up the masthead has exactly one width to fit in and
947
+ wrapping there is not a fallback, it is a permanent second line - one tab
948
+ too many and the last item in source order drops, on a 4K display as surely
949
+ as on a laptop. So the wide row does not wrap; it takes the width out of the
950
+ search field instead (below), and the strip scrolls only if that runs out.
951
+ Under the cap the window really is too narrow and wrapping is the honest
952
+ answer, which is why this is a floor and not a blanket `nowrap`. */
953
+ @media (min-width: 1280px) {
954
+ .axi-mast__in { flex-wrap: nowrap; }
955
+ }
956
+ /* Nothing in the row gives up width unless it is named below. */
957
+ .axi-mast__in > * { flex-shrink: 0; }
958
+ /* The field is the one control here that is still entirely itself 70px
959
+ narrower - a placeholder that elides costs nothing, where a clipped tab
960
+ costs a destination. Flexbox shrinks proportionally, not in order, and a
961
+ merely-larger factor still took a couple of pixels off the last tab; the
962
+ number is this big to make that share round to nothing, so the effect is
963
+ the ordering CSS has no other way to say. Once the field is at its floor -
964
+ still wide enough to read as a search box rather than a smudge - whatever
965
+ is left over goes to the strip, which scrolls. */
966
+ .axi-mast .axi-search,
967
+ .axi-mast .docs-search { flex-shrink: 1000; min-width: 200px; }
925
968
  .axi-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
926
969
  /* The sigil is the diamond motif scaled up with a glyph on top. The diamond is
927
970
  a rotated pseudo-element behind the text rather than a rotated box, so the
@@ -955,8 +998,14 @@ textarea.axi-input {
955
998
  .axi-tabs { display: flex; gap: 8px; }
956
999
  /* The auto margin belongs to the masthead, not to the strip: it is a statement
957
1000
  about where the tabs sit in that row, and a strip standing on its own -
958
- spanning a view instead of ending a header - has nothing to push away from. */
959
- .axi-mast .axi-tabs { margin-left: auto; }
1001
+ spanning a view instead of ending a header - has nothing to push away from.
1002
+ The overflow belongs to the masthead for the same reason. This row is capped
1003
+ at --axi-page, so the brand, the strip, the search field and the two selects
1004
+ divide 1244px however wide the window is, and flex-wrap breaks a line before
1005
+ it shrinks an item - so one tab too many sent the last item in source order
1006
+ to a second row instead of taking width off the widest one. The strip is the
1007
+ item that can give: it scrolls, and the row stays a row. */
1008
+ .axi-mast .axi-tabs { margin-left: auto; flex-shrink: 1; min-width: 0; overflow-x: auto; }
960
1009
  .axi-tabs a,
961
1010
  .axi-tabs button {
962
1011
  padding: 8px 16px;
@@ -1051,6 +1100,14 @@ textarea.axi-input {
1051
1100
  border-right: var(--axi-border-panel) solid var(--axi-ink-line);
1052
1101
  border-radius: 0;
1053
1102
  }
1103
+ /* A rail the page scrolls behind, rather than one the page sits beside.
1104
+ It is the same object, so it keeps every other rule; the one thing that
1105
+ changes is the surface it is printed on. --axi-surface is a translucent
1106
+ tint under a theme like glass, which reads as a pane only while the
1107
+ content behind it holds still — the moment a table scrolls past, the
1108
+ rows show through the nav. --axi-surface-float is the surface for
1109
+ exactly that case, so say it once here instead of in each consumer. */
1110
+ .axi-rail--float { background: var(--axi-surface-float); }
1054
1111
  .axi-rail__nav { display: flex; flex-direction: column; gap: 2px; }
1055
1112
  .axi-rail__item {
1056
1113
  display: flex;
@@ -1329,6 +1386,22 @@ textarea.axi-input {
1329
1386
  white-space: nowrap;
1330
1387
  pointer-events: none;
1331
1388
  }
1389
+ /* Positioned by the thing it describes rather than by the cursor. The <body>
1390
+ contract above is what position: fixed costs; a tooltip that belongs to one
1391
+ trigger can be a child of it instead, and then it wants the trigger's
1392
+ coordinate space. Rule 4's transformed ancestor is the reason fixed cannot
1393
+ live there - absolute is anchored to exactly that ancestor, so a hover lift
1394
+ carries the tooltip with it instead of stranding it.
1395
+
1396
+ The consumer supplies the offsets (a `position: relative` trigger and the
1397
+ left/top or inset the placement needs); this only changes which box those
1398
+ offsets are measured from. */
1399
+ .axi-tooltip--anchored { position: absolute; }
1400
+ /* A tooltip carrying a sentence rather than a value. nowrap is right for a
1401
+ reading - a number that breaks across two lines is harder to read than one
1402
+ that runs past its trigger - and wrong for prose, which needs a width from
1403
+ the consumer to wrap inside. */
1404
+ .axi-tooltip--wrap { white-space: normal; }
1332
1405
 
1333
1406
  /* ---------- card ---------- */
1334
1407
  .axi-card {
@@ -27,4 +27,5 @@
27
27
  --axi-border-hairline: 1px;
28
28
  --axi-radius: 16px;
29
29
  --axi-radius-sm: 10px;
30
+ --axi-radius-xs: 4px;
30
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiapps/axi-design",
3
- "version": "1.18.0",
3
+ "version": "1.20.0",
4
4
  "description": "The design language for the axi suite — flat and outlined, dark, drawn in saturated ink.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/forms.css CHANGED
@@ -36,7 +36,10 @@
36
36
  place-items: center;
37
37
  background: var(--axi-ground);
38
38
  border: var(--axi-border-control) solid var(--axi-ink-line);
39
- border-radius: var(--axi-radius-sm);
39
+ /* The text-sized step, not the control-sized one - see --axi-radius-xs in
40
+ src/tokens.css for why a 22px box cannot take a corner scaled for a 36px
41
+ button. */
42
+ border-radius: var(--axi-radius-xs);
40
43
  cursor: pointer;
41
44
  }
42
45
  /* The mark is always in the DOM and revealed with opacity rather than being
@@ -28,6 +28,15 @@
28
28
  fit is genuinely called for. */
29
29
  padding: var(--axi-panel-pad, 26px);
30
30
  }
31
+ /* A panel that floats over moving content rather than sitting in the page: a
32
+ readout pinned to a chart, a popover over a scrolling table. Same object,
33
+ same everything else; the one thing that changes is the surface it is
34
+ printed on. --axi-surface is a translucent tint under a theme like glass,
35
+ which reads as a pane only while what is behind it holds still - the moment
36
+ the content scrolls, it shows through the panel. --axi-surface-float is the
37
+ surface for exactly that case. Says the same thing .axi-rail--float says,
38
+ on the other surface that needs it. */
39
+ .axi-panel--float { background: var(--axi-surface-float); }
31
40
 
32
41
  /* ---------- well ---------- */
33
42
  /* The panel's inverse: a field sunk into the surface around it rather than
package/src/shells.css CHANGED
@@ -23,6 +23,29 @@
23
23
  padding-inline: var(--axi-gutter);
24
24
  display: flex; align-items: center; gap: 22px; min-height: 66px; flex-wrap: wrap;
25
25
  }
26
+ /* Above --axi-page the row stops growing: the cap is on this box, not on the
27
+ window, so from 1280px up the masthead has exactly one width to fit in and
28
+ wrapping there is not a fallback, it is a permanent second line - one tab
29
+ too many and the last item in source order drops, on a 4K display as surely
30
+ as on a laptop. So the wide row does not wrap; it takes the width out of the
31
+ search field instead (below), and the strip scrolls only if that runs out.
32
+ Under the cap the window really is too narrow and wrapping is the honest
33
+ answer, which is why this is a floor and not a blanket `nowrap`. */
34
+ @media (min-width: 1280px) {
35
+ .axi-mast__in { flex-wrap: nowrap; }
36
+ }
37
+ /* Nothing in the row gives up width unless it is named below. */
38
+ .axi-mast__in > * { flex-shrink: 0; }
39
+ /* The field is the one control here that is still entirely itself 70px
40
+ narrower - a placeholder that elides costs nothing, where a clipped tab
41
+ costs a destination. Flexbox shrinks proportionally, not in order, and a
42
+ merely-larger factor still took a couple of pixels off the last tab; the
43
+ number is this big to make that share round to nothing, so the effect is
44
+ the ordering CSS has no other way to say. Once the field is at its floor -
45
+ still wide enough to read as a search box rather than a smudge - whatever
46
+ is left over goes to the strip, which scrolls. */
47
+ .axi-mast .axi-search,
48
+ .axi-mast .docs-search { flex-shrink: 1000; min-width: 200px; }
26
49
  .axi-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
27
50
  /* The sigil is the diamond motif scaled up with a glyph on top. The diamond is
28
51
  a rotated pseudo-element behind the text rather than a rotated box, so the
@@ -56,8 +79,14 @@
56
79
  .axi-tabs { display: flex; gap: 8px; }
57
80
  /* The auto margin belongs to the masthead, not to the strip: it is a statement
58
81
  about where the tabs sit in that row, and a strip standing on its own -
59
- spanning a view instead of ending a header - has nothing to push away from. */
60
- .axi-mast .axi-tabs { margin-left: auto; }
82
+ spanning a view instead of ending a header - has nothing to push away from.
83
+ The overflow belongs to the masthead for the same reason. This row is capped
84
+ at --axi-page, so the brand, the strip, the search field and the two selects
85
+ divide 1244px however wide the window is, and flex-wrap breaks a line before
86
+ it shrinks an item - so one tab too many sent the last item in source order
87
+ to a second row instead of taking width off the widest one. The strip is the
88
+ item that can give: it scrolls, and the row stays a row. */
89
+ .axi-mast .axi-tabs { margin-left: auto; flex-shrink: 1; min-width: 0; overflow-x: auto; }
61
90
  .axi-tabs a,
62
91
  .axi-tabs button {
63
92
  padding: 8px 16px;
@@ -152,6 +181,14 @@
152
181
  border-right: var(--axi-border-panel) solid var(--axi-ink-line);
153
182
  border-radius: 0;
154
183
  }
184
+ /* A rail the page scrolls behind, rather than one the page sits beside.
185
+ It is the same object, so it keeps every other rule; the one thing that
186
+ changes is the surface it is printed on. --axi-surface is a translucent
187
+ tint under a theme like glass, which reads as a pane only while the
188
+ content behind it holds still — the moment a table scrolls past, the
189
+ rows show through the nav. --axi-surface-float is the surface for
190
+ exactly that case, so say it once here instead of in each consumer. */
191
+ .axi-rail--float { background: var(--axi-surface-float); }
155
192
  .axi-rail__nav { display: flex; flex-direction: column; gap: 2px; }
156
193
  .axi-rail__item {
157
194
  display: flex;
@@ -430,6 +467,22 @@
430
467
  white-space: nowrap;
431
468
  pointer-events: none;
432
469
  }
470
+ /* Positioned by the thing it describes rather than by the cursor. The <body>
471
+ contract above is what position: fixed costs; a tooltip that belongs to one
472
+ trigger can be a child of it instead, and then it wants the trigger's
473
+ coordinate space. Rule 4's transformed ancestor is the reason fixed cannot
474
+ live there - absolute is anchored to exactly that ancestor, so a hover lift
475
+ carries the tooltip with it instead of stranding it.
476
+
477
+ The consumer supplies the offsets (a `position: relative` trigger and the
478
+ left/top or inset the placement needs); this only changes which box those
479
+ offsets are measured from. */
480
+ .axi-tooltip--anchored { position: absolute; }
481
+ /* A tooltip carrying a sentence rather than a value. nowrap is right for a
482
+ reading - a number that breaks across two lines is harder to read than one
483
+ that runs past its trigger - and wrong for prose, which needs a width from
484
+ the consumer to wrap inside. */
485
+ .axi-tooltip--wrap { white-space: normal; }
433
486
 
434
487
  /* ---------- card ---------- */
435
488
  .axi-card {
package/src/tokens.css CHANGED
@@ -140,6 +140,14 @@
140
140
  control-sized reads --axi-radius-sm. */
141
141
  --axi-radius: 0;
142
142
  --axi-radius-sm: 0;
143
+ /* The third step, for a box the size of the text beside it: a checkbox, a
144
+ radio. --axi-radius-sm is sized for something you press - a button, an
145
+ input, 36px tall - and a theme is free to set it to 10px. On a 22px
146
+ square 10px is most of the box: the checkbox stops being a square and
147
+ becomes a circle, and a circle next to rule 7's diamond radio is the one
148
+ shape confusion this pair exists to avoid. A theme that wants soft
149
+ corners sets all three. */
150
+ --axi-radius-xs: 0;
143
151
  /* Not a form step: a hairline used inside prose (inline code, table rules,
144
152
  the list bullet) where the two form steps above would read as too heavy
145
153
  for a line of running text. */