@axiapps/axi-design 1.20.0 → 1.21.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
@@ -1842,7 +1842,11 @@ textarea.axi-input {
1842
1842
  .axi-table td { text-align: right; white-space: nowrap; }
1843
1843
  .axi-table th:first-child,
1844
1844
  .axi-table td:first-child { text-align: left; }
1845
- .axi-table th {
1845
+ /* `thead th`, not `th`. A row's name is a `<th scope="row">` - that is what
1846
+ tells a screen reader which cell labels the row - and it is a name, not a
1847
+ column heading: uppercase micro type down the first column would shout every
1848
+ row's label at the reader. A row header takes the cell treatment below. */
1849
+ .axi-table thead th {
1846
1850
  padding: 0 10px 10px;
1847
1851
  font: var(--axi-t-micro);
1848
1852
  letter-spacing: var(--axi-ls-micro);
@@ -1850,7 +1854,8 @@ textarea.axi-input {
1850
1854
  color: var(--axi-text-faint);
1851
1855
  border-bottom: var(--axi-border-control) solid var(--axi-rule);
1852
1856
  }
1853
- .axi-table td {
1857
+ .axi-table td,
1858
+ .axi-table tbody th {
1854
1859
  padding: 9px 10px;
1855
1860
  font: var(--axi-t-small);
1856
1861
  font-weight: 700;
@@ -1861,7 +1866,7 @@ textarea.axi-input {
1861
1866
  hovering a row is not a status, and forty rows that each flash a colour on
1862
1867
  the way past the one you want is the tinted-everything failure rule 2 is
1863
1868
  about. */
1864
- .axi-table tbody tr:hover td { background: var(--axi-surface-raised); color: var(--axi-text); }
1869
+ .axi-table tbody tr:hover :is(td, th) { background: var(--axi-surface-raised); color: var(--axi-text); }
1865
1870
  /* The measured value in a row, as opposed to its supporting numbers. */
1866
1871
  .axi-table__num { color: var(--axi-text); }
1867
1872
  /* A name cell: an icon, a diamond or a rank beside the label. */
@@ -1879,6 +1884,93 @@ textarea.axi-input {
1879
1884
  }
1880
1885
  .axi-table__rank--top { background: var(--axi-accent); color: var(--axi-accent-ink); }
1881
1886
 
1887
+ /* A table too wide and too tall for the panel holding it: twenty numeric
1888
+ columns against forty players, scrolled in both directions. Rule 8 still
1889
+ decides what every line means - the head is a lid at the control step, the
1890
+ rows are hairlines - and the only new thing here is that the lid and the
1891
+ row's name have to stay put while the numbers move under them.
1892
+
1893
+ `border-collapse: separate` is load-bearing, not housekeeping. A collapsed
1894
+ table hoists its cell borders onto the table itself, and a border owned by
1895
+ the table scrolls away with it, so a sticky head drawn under `collapse`
1896
+ loses the very line that makes it a lid. Separate borders stay with the
1897
+ cell that declared them. Each modifier sets it, so either works alone.
1898
+
1899
+ Note what is NOT here. No block: an edge that has to hold under scrolling
1900
+ is a border, and a block in this language is an offset rectangle, which is
1901
+ not the shape of the top of a column. No scrolled-under state either - the
1902
+ head's edge is drawn whether anything has moved beneath it or not, so there
1903
+ is nothing for scrolling to reveal. */
1904
+ /* The isolation is the reason the three z-indexes below can be 1, 2 and 3:
1905
+ they are resolved in here and cannot compete with the page stack. See the
1906
+ layer table in docs/RULES.md. */
1907
+ .axi-table__scroll { overflow: auto; isolation: isolate; }
1908
+ /* The head stays. */
1909
+ .axi-table--sticky { border-collapse: separate; border-spacing: 0; }
1910
+ .axi-table--sticky thead th {
1911
+ position: sticky;
1912
+ top: 0;
1913
+ z-index: 2;
1914
+ /* The float surface, not the raised one, and this is the whole reason
1915
+ --axi-surface-float exists: rows travel behind both of these, and a glass
1916
+ theme's ordinary surfaces are alpha, so a head at --axi-surface-raised
1917
+ would have numbers sliding through it. Opaque is not a look here, it is
1918
+ the requirement. */
1919
+ background: var(--axi-surface-float);
1920
+ border-bottom: var(--axi-border-control) solid var(--axi-ink-line);
1921
+ }
1922
+ /* The first column stays. It holds the row's name, and a name scrolled out of
1923
+ sight makes every number left of it anonymous - which is the whole reason a
1924
+ wide table is readable at all. Its edge is the cut the head carries, turned
1925
+ ninety degrees. */
1926
+ .axi-table--pinned { border-collapse: separate; border-spacing: 0; }
1927
+ .axi-table--pinned :is(thead, tbody) :is(th, td):first-child {
1928
+ position: sticky;
1929
+ left: 0;
1930
+ z-index: 1;
1931
+ background: var(--axi-surface-float);
1932
+ border-right: var(--axi-border-control) solid var(--axi-ink-line);
1933
+ }
1934
+ /* The corner belongs to both and has to outrank both. */
1935
+ .axi-table--sticky.axi-table--pinned thead th:first-child { z-index: 3; }
1936
+ /* Twenty columns do not get a leaderboard's padding. The type steps down with
1937
+ them; everything else about the table is unchanged, which is the point of
1938
+ its being a modifier rather than a second table. */
1939
+ .axi-table--dense thead th { padding: 0 7px 6px; }
1940
+ .axi-table--dense :is(td, tbody th) { padding: 5px 7px; font: var(--axi-t-micro); }
1941
+ /* The sorted column, named with the attribute a screen reader already needs
1942
+ in order to announce it. A class beside `aria-sort` would be a second
1943
+ source of truth for one fact. The mark is ink on the head and its edge -
1944
+ not a fill down the column, which is rule 2's tinted-everything failure
1945
+ applied to the one column you are trying to read. */
1946
+ .axi-table th[aria-sort] {
1947
+ color: var(--axi-accent);
1948
+ border-bottom-color: var(--axi-accent);
1949
+ }
1950
+ /* CSS cannot reach "the cells under the sorted head", so the consumer marks
1951
+ them. Full-strength text against the column's dimmed neighbours. */
1952
+ .axi-table__cell--sorted { color: var(--axi-text); }
1953
+ /* A sortable heading is a button, because sorting is an action and a <th> you
1954
+ can click but not tab to is a column the keyboard cannot sort. It inherits
1955
+ everything and adds nothing, so a heading looks the same whether it sorts or
1956
+ not - the only thing that marks a sorted column is aria-sort above. */
1957
+ .axi-table__sort {
1958
+ display: flex;
1959
+ align-items: center;
1960
+ justify-content: flex-end;
1961
+ gap: 6px;
1962
+ width: 100%;
1963
+ padding: 0;
1964
+ background: none;
1965
+ border: 0;
1966
+ font: inherit;
1967
+ color: inherit;
1968
+ letter-spacing: inherit;
1969
+ text-transform: inherit;
1970
+ cursor: pointer;
1971
+ }
1972
+ .axi-table th:first-child .axi-table__sort { justify-content: flex-start; }
1973
+
1882
1974
  /* ---------- meter ---------- */
1883
1975
  /* Rule 9: a proportion is a length. The track is the ground, the fill is the
1884
1976
  value, and the fill is one ink at full strength - a tinted or faded bar is
package/docs/RULES.md CHANGED
@@ -461,6 +461,9 @@ instead of joining it.
461
461
 
462
462
  | Layer | z-index | What sits here |
463
463
  |---|---|---|
464
+ | Pinned column | 1 | `.axi-table--pinned`'s first column |
465
+ | Sticky head | 2 | `.axi-table--sticky`'s `thead th` |
466
+ | Table corner | 3 | where the two cross |
464
467
  | Sticky chrome | 40 | `.axi-mast` |
465
468
  | Popovers | 41 | `.axi-menu__pop`, `.axi-picker__pop` |
466
469
  | Scrim | 50 | `.axi-scrim` |
@@ -473,6 +476,15 @@ The modal has no number on purpose. A `<dialog>` opened with `showModal()` is
473
476
  promoted to the browser's top layer, which sits above every `z-index` there is;
474
477
  writing a number in that row would describe a competition the modal is not in.
475
478
 
479
+ The first three are sealed rather than low. `.axi-table__scroll` sets
480
+ `isolation: isolate`, so those numbers are resolved inside the scroll container
481
+ and never compete with the page layers under them - a table's sticky head
482
+ cannot climb over a mast, and a table inside a drawer cannot reach out of it.
483
+ They are listed because a table needs three orderings among its own cells and a
484
+ number that is never written down is a number that drifts; the isolation is
485
+ what keeps 1, 2 and 3 from meaning anything outside the table that declares
486
+ them.
487
+
476
488
  A negative `z-index` inside a component's own `isolation` context — the sigil's
477
489
  backing shape — is not a layer and is not listed. It is invisible outside the
478
490
  component that owns it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiapps/axi-design",
3
- "version": "1.20.0",
3
+ "version": "1.21.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/data.css CHANGED
@@ -64,7 +64,11 @@
64
64
  .axi-table td { text-align: right; white-space: nowrap; }
65
65
  .axi-table th:first-child,
66
66
  .axi-table td:first-child { text-align: left; }
67
- .axi-table th {
67
+ /* `thead th`, not `th`. A row's name is a `<th scope="row">` - that is what
68
+ tells a screen reader which cell labels the row - and it is a name, not a
69
+ column heading: uppercase micro type down the first column would shout every
70
+ row's label at the reader. A row header takes the cell treatment below. */
71
+ .axi-table thead th {
68
72
  padding: 0 10px 10px;
69
73
  font: var(--axi-t-micro);
70
74
  letter-spacing: var(--axi-ls-micro);
@@ -72,7 +76,8 @@
72
76
  color: var(--axi-text-faint);
73
77
  border-bottom: var(--axi-border-control) solid var(--axi-rule);
74
78
  }
75
- .axi-table td {
79
+ .axi-table td,
80
+ .axi-table tbody th {
76
81
  padding: 9px 10px;
77
82
  font: var(--axi-t-small);
78
83
  font-weight: 700;
@@ -83,7 +88,7 @@
83
88
  hovering a row is not a status, and forty rows that each flash a colour on
84
89
  the way past the one you want is the tinted-everything failure rule 2 is
85
90
  about. */
86
- .axi-table tbody tr:hover td { background: var(--axi-surface-raised); color: var(--axi-text); }
91
+ .axi-table tbody tr:hover :is(td, th) { background: var(--axi-surface-raised); color: var(--axi-text); }
87
92
  /* The measured value in a row, as opposed to its supporting numbers. */
88
93
  .axi-table__num { color: var(--axi-text); }
89
94
  /* A name cell: an icon, a diamond or a rank beside the label. */
@@ -101,6 +106,93 @@
101
106
  }
102
107
  .axi-table__rank--top { background: var(--axi-accent); color: var(--axi-accent-ink); }
103
108
 
109
+ /* A table too wide and too tall for the panel holding it: twenty numeric
110
+ columns against forty players, scrolled in both directions. Rule 8 still
111
+ decides what every line means - the head is a lid at the control step, the
112
+ rows are hairlines - and the only new thing here is that the lid and the
113
+ row's name have to stay put while the numbers move under them.
114
+
115
+ `border-collapse: separate` is load-bearing, not housekeeping. A collapsed
116
+ table hoists its cell borders onto the table itself, and a border owned by
117
+ the table scrolls away with it, so a sticky head drawn under `collapse`
118
+ loses the very line that makes it a lid. Separate borders stay with the
119
+ cell that declared them. Each modifier sets it, so either works alone.
120
+
121
+ Note what is NOT here. No block: an edge that has to hold under scrolling
122
+ is a border, and a block in this language is an offset rectangle, which is
123
+ not the shape of the top of a column. No scrolled-under state either - the
124
+ head's edge is drawn whether anything has moved beneath it or not, so there
125
+ is nothing for scrolling to reveal. */
126
+ /* The isolation is the reason the three z-indexes below can be 1, 2 and 3:
127
+ they are resolved in here and cannot compete with the page stack. See the
128
+ layer table in docs/RULES.md. */
129
+ .axi-table__scroll { overflow: auto; isolation: isolate; }
130
+ /* The head stays. */
131
+ .axi-table--sticky { border-collapse: separate; border-spacing: 0; }
132
+ .axi-table--sticky thead th {
133
+ position: sticky;
134
+ top: 0;
135
+ z-index: 2;
136
+ /* The float surface, not the raised one, and this is the whole reason
137
+ --axi-surface-float exists: rows travel behind both of these, and a glass
138
+ theme's ordinary surfaces are alpha, so a head at --axi-surface-raised
139
+ would have numbers sliding through it. Opaque is not a look here, it is
140
+ the requirement. */
141
+ background: var(--axi-surface-float);
142
+ border-bottom: var(--axi-border-control) solid var(--axi-ink-line);
143
+ }
144
+ /* The first column stays. It holds the row's name, and a name scrolled out of
145
+ sight makes every number left of it anonymous - which is the whole reason a
146
+ wide table is readable at all. Its edge is the cut the head carries, turned
147
+ ninety degrees. */
148
+ .axi-table--pinned { border-collapse: separate; border-spacing: 0; }
149
+ .axi-table--pinned :is(thead, tbody) :is(th, td):first-child {
150
+ position: sticky;
151
+ left: 0;
152
+ z-index: 1;
153
+ background: var(--axi-surface-float);
154
+ border-right: var(--axi-border-control) solid var(--axi-ink-line);
155
+ }
156
+ /* The corner belongs to both and has to outrank both. */
157
+ .axi-table--sticky.axi-table--pinned thead th:first-child { z-index: 3; }
158
+ /* Twenty columns do not get a leaderboard's padding. The type steps down with
159
+ them; everything else about the table is unchanged, which is the point of
160
+ its being a modifier rather than a second table. */
161
+ .axi-table--dense thead th { padding: 0 7px 6px; }
162
+ .axi-table--dense :is(td, tbody th) { padding: 5px 7px; font: var(--axi-t-micro); }
163
+ /* The sorted column, named with the attribute a screen reader already needs
164
+ in order to announce it. A class beside `aria-sort` would be a second
165
+ source of truth for one fact. The mark is ink on the head and its edge -
166
+ not a fill down the column, which is rule 2's tinted-everything failure
167
+ applied to the one column you are trying to read. */
168
+ .axi-table th[aria-sort] {
169
+ color: var(--axi-accent);
170
+ border-bottom-color: var(--axi-accent);
171
+ }
172
+ /* CSS cannot reach "the cells under the sorted head", so the consumer marks
173
+ them. Full-strength text against the column's dimmed neighbours. */
174
+ .axi-table__cell--sorted { color: var(--axi-text); }
175
+ /* A sortable heading is a button, because sorting is an action and a <th> you
176
+ can click but not tab to is a column the keyboard cannot sort. It inherits
177
+ everything and adds nothing, so a heading looks the same whether it sorts or
178
+ not - the only thing that marks a sorted column is aria-sort above. */
179
+ .axi-table__sort {
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: flex-end;
183
+ gap: 6px;
184
+ width: 100%;
185
+ padding: 0;
186
+ background: none;
187
+ border: 0;
188
+ font: inherit;
189
+ color: inherit;
190
+ letter-spacing: inherit;
191
+ text-transform: inherit;
192
+ cursor: pointer;
193
+ }
194
+ .axi-table th:first-child .axi-table__sort { justify-content: flex-start; }
195
+
104
196
  /* ---------- meter ---------- */
105
197
  /* Rule 9: a proportion is a length. The track is the ground, the fill is the
106
198
  value, and the fill is one ink at full strength - a tinted or faded bar is