@waveso/docs 0.9.1 → 0.11.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/CHANGELOG.md +539 -0
- package/README.md +99 -3
- package/dist/code-frame.d.ts +28 -1
- package/dist/code-frame.js +36 -1
- package/dist/frontmatter.d.ts +5 -0
- package/dist/frontmatter.js +5 -0
- package/dist/nav-order.d.ts +43 -0
- package/dist/nav-order.js +72 -0
- package/dist/next.d.ts +10 -0
- package/dist/next.js +33 -0
- package/dist/plugins/rehype-code-frame.js +41 -11
- package/dist/react/explore.d.ts +53 -0
- package/dist/react/explore.js +86 -0
- package/dist/react/markdown-components.js +14 -0
- package/dist/react/pager.d.ts +42 -0
- package/dist/react/pager.js +91 -0
- package/dist/react/shell-labels.d.ts +25 -1
- package/dist/react/shell-labels.js +4 -0
- package/dist/react/toc.js +34 -5
- package/dist/styles.css +944 -146
- package/dist/types.d.ts +31 -1
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,544 @@
|
|
|
1
1
|
# @waveso/docs
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5730af3: **The code frame wears the panel.** A fence is now an outer card holding a
|
|
8
|
+
header row — the filename or the language on the left, the copy button on the
|
|
9
|
+
right — and an inset surface with the code on it, dressed by the same
|
|
10
|
+
`.wave-docs-panel` rules as "where to go next".
|
|
11
|
+
|
|
12
|
+
⚠️ THE `<figcaption>` STAYS A DIRECT CHILD OF THE `<figure>`, WHICH IS WHY THIS
|
|
13
|
+
HAS NO HEADER WRAPPER. A `figcaption` has to be the first or last child of its
|
|
14
|
+
figure; inside the `.wave-docs-panel__header` `<div>` that "where to go next"
|
|
15
|
+
uses it captions nothing, the markup is invalid, and a titled block loses the
|
|
16
|
+
accessible name it had. So the frame lays its header out on a grid and shares
|
|
17
|
+
the primitive's _insets_ rather than its header element. The button stays out of
|
|
18
|
+
the caption for the matching reason: a `<button>` inside a `<figcaption>`
|
|
19
|
+
contributes its accessible name to the figure's, so `swap.ts` would announce as
|
|
20
|
+
"swap.ts Copy code from swap.ts".
|
|
21
|
+
|
|
22
|
+
⚠️ AND A TITLE IS WHAT DECIDES WHETHER THERE IS A FRAME AT ALL. With one, the
|
|
23
|
+
figure is a panel: a band carrying the filename and the copy button, and the
|
|
24
|
+
code set into a card below it. With none there is nothing to put in a band, so
|
|
25
|
+
the frame flattens away, the surface becomes the block, and the button sits on
|
|
26
|
+
the code — which is what Mintlify does, and what stops an unnamed fence from
|
|
27
|
+
carrying a reserved slot with nothing in it.
|
|
28
|
+
|
|
29
|
+
A language is not a title for this purpose. A fence declaring `ts` and no
|
|
30
|
+
filename is still an untitled fence, and a band holding a two-letter badge is
|
|
31
|
+
the same empty header with a word in it. `data-lang` stays on the figure for
|
|
32
|
+
anyone selecting on it.
|
|
33
|
+
|
|
34
|
+
One shape of markup, switched in the stylesheet rather than in the pipeline: two
|
|
35
|
+
markup paths mean two fixtures, and the one that is not on screen is the one
|
|
36
|
+
that rots.
|
|
37
|
+
|
|
38
|
+
**The copy button no longer hides until you hover.** It faded in on `:hover` or
|
|
39
|
+
`:focus-within` because it was positioned over the code and had nowhere of its
|
|
40
|
+
own to be. It has a slot in the header row now, and a reserved slot that stays
|
|
41
|
+
empty until you point at it reads as a rendering fault — so the reveal, the
|
|
42
|
+
`@media (hover: none)` exception that existed because a hover-only control does
|
|
43
|
+
not exist on a phone, and the reduced-motion guard on its transition all went
|
|
44
|
+
with it. It is still `visibility: hidden` until the runtime attaches, which is
|
|
45
|
+
the structural promise and is unchanged.
|
|
46
|
+
|
|
47
|
+
## Three things the restructure moved, each of which was a defect
|
|
48
|
+
|
|
49
|
+
⚠️ THE `<pre>` DRAWS NO FRAME OF ITS OWN ANY MORE. It carried the border, the
|
|
50
|
+
radius and the background; inside a `.wave-docs-panel__body` that carries all
|
|
51
|
+
three, that draws the frame twice one pixel apart. `pre:not(.shiki)` keeps its
|
|
52
|
+
own, because an excluded fence is never wrapped.
|
|
53
|
+
|
|
54
|
+
⚠️ AND ITS INLINE PADDING IS `1rem` BECAUSE THAT IS `--wave-docs-panel-inset`,
|
|
55
|
+
not because it is a round number. The label sits at that inset plus the
|
|
56
|
+
surface's border; the code sits at the surface's border plus this. The
|
|
57
|
+
`1.125rem` it was put the first character 2px right of the filename above it —
|
|
58
|
+
visible, and attributable to nothing.
|
|
59
|
+
|
|
60
|
+
⚠️ AND THE FOCUS RING ON THE `<pre>` IS INSET NOW. Shiki gives it
|
|
61
|
+
`tabindex="0"` so a keyboard reader can scroll a wide block, and the surface
|
|
62
|
+
around it is `overflow: hidden` so a square corner cannot poke through the
|
|
63
|
+
frame's rounded one — which clipped a `+2px` outline away to nothing.
|
|
64
|
+
`styles.test.ts` reads rules as text and would have gone on passing.
|
|
65
|
+
|
|
66
|
+
## The panel grew two properties, both to settle a cascade rather than a taste
|
|
67
|
+
|
|
68
|
+
`--wave-docs-panel-surface` is the inset surface's ground, and its default lives
|
|
69
|
+
in a `var()` fallback rather than in a declaration. `.wave-docs-code__body` and
|
|
70
|
+
`.wave-docs-panel__body` are both one class, so source order decides and the
|
|
71
|
+
panel is declared later: a code frame asking for the darker code ground got the
|
|
72
|
+
panel's white. Moving the ground to a property did not fix it either — a frame
|
|
73
|
+
wears `.wave-docs-panel` _and_ `.wave-docs-code`, so both rules set that property
|
|
74
|
+
on the same element at the same specificity, and source order handed it back.
|
|
75
|
+
Measured twice as `oklch(1 0 0)` where `oklch(0.975 0.003 262)` was written. In
|
|
76
|
+
the fallback there is no declaration to lose to.
|
|
77
|
+
|
|
78
|
+
`--wave-docs-panel-header-row` floors the header. With a label the row is the
|
|
79
|
+
label's height and with none it is the button's, and a page mixing titled and
|
|
80
|
+
untitled fences showed two header heights.
|
|
81
|
+
|
|
82
|
+
The frame's markup now has one home — `codeFrameMarkup` — that the browser tier
|
|
83
|
+
mounts and the plugin tier asserts the pipeline agrees with. Written out
|
|
84
|
+
separately in both, a hand-written fixture goes on describing a frame the
|
|
85
|
+
pipeline stopped emitting while every assertion measuring it stays green.
|
|
86
|
+
|
|
87
|
+
- 793d0f7: **"Where to go next": a question per row, and the page that answers it.** A page
|
|
88
|
+
opts in from its frontmatter:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
explore:
|
|
92
|
+
- question: How a person is recognised across servers
|
|
93
|
+
href: ./identity.md
|
|
94
|
+
- question: What happens when the network fails
|
|
95
|
+
href: ./delivery.md
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
A sidebar is a structure; this is a router. It says _why_ a reader would go
|
|
99
|
+
somewhere, which no tree of titles can — so the same component is a landing
|
|
100
|
+
page's onboarding and an ordinary page's footnote.
|
|
101
|
+
|
|
102
|
+
⚠️ THE LINK TEXT COMES FROM THE NAVIGATION. An `href` pointing at a page in the
|
|
103
|
+
tree takes that page's own name, so renaming it updates every block that points
|
|
104
|
+
at it — the same tree the sidebar and the pager read. Name a `title` only where
|
|
105
|
+
the tree cannot answer: an external link, or a page kept out of the navigation.
|
|
106
|
+
|
|
107
|
+
⚠️ AND AN HREF THAT RESOLVES TO NEITHER STOPS THE BUILD. Falling back to the
|
|
108
|
+
href renders a URL where a sentence should be — "Where this runs and what that
|
|
109
|
+
buys → /docs/infrastructure" — on a page that builds cleanly, and nothing else
|
|
110
|
+
in the pipeline would notice. The frontmatter is authored and the author is
|
|
111
|
+
right there, so the error names the page and both fixes.
|
|
112
|
+
|
|
113
|
+
⚠️ A LIST, NOT A TABLE, WHICH IS WHAT THE MARKDOWN IT REPLACES HAD TO BE. A
|
|
114
|
+
screen reader announces "table, 2 columns, 7 rows" for what is a list of links
|
|
115
|
+
with descriptions, and asks the reader to navigate it by cell. Two columns of
|
|
116
|
+
sentence-length questions are also cramped in a narrow box, where the rows stack
|
|
117
|
+
instead — a `@container` query, because a host can hand this a 500px panel on a
|
|
118
|
+
1920px monitor.
|
|
119
|
+
|
|
120
|
+
One frame with hairlines between the rows rather than a stack of cards: they are
|
|
121
|
+
the same question asked several ways, and separate boxes say several unrelated
|
|
122
|
+
things. The rule is a _top_ border on every row but the first — `:last-child`
|
|
123
|
+
leaves a doubled line the moment anything is appended to the list.
|
|
124
|
+
|
|
125
|
+
## And the frame is a primitive, not this component's furniture
|
|
126
|
+
|
|
127
|
+
`.wave-docs-panel` is a framed block with a header and an inset surface — the
|
|
128
|
+
outer card names the thing and carries its controls, the inner one holds the
|
|
129
|
+
content. "Where to go next" is the first thing to wear it; a code frame is the
|
|
130
|
+
obvious next, and two copies of the same three rules is how they drift apart.
|
|
131
|
+
|
|
132
|
+
⚠️ THE TWO RADII ARE NOT INDEPENDENT NUMBERS. A rounded box inside a rounded box
|
|
133
|
+
only looks right when the inner radius is the outer one minus the gap between
|
|
134
|
+
them; anything else runs the corners at different curvatures and the inner box
|
|
135
|
+
reads as _pasted onto_ the frame rather than set into it. The new
|
|
136
|
+
`--wave-docs-radius-lg` is chosen so the arithmetic lands on an existing token:
|
|
137
|
+
`1rem` outer minus `0.5rem` of padding is `--wave-docs-radius`.
|
|
138
|
+
|
|
139
|
+
The header sits in the frame's padding and draws no rule of its own — the inset
|
|
140
|
+
surface below already draws the line, and a border there is a second one a pixel
|
|
141
|
+
away from the first.
|
|
142
|
+
|
|
143
|
+
⚠️ AND THE PANEL EXPORTS `--wave-docs-panel-inset`, WHICH IS NOT THE SAME NUMBER
|
|
144
|
+
AS ITS PADDING. The title sits at the frame's padding; anything inside the body
|
|
145
|
+
sits at that padding _plus the body's own border_, so the two columns miss each
|
|
146
|
+
other by a pixel per border. Measured before it existed: the rows started 9px
|
|
147
|
+
right of the heading above them — a number that appears in no rule and reads as
|
|
148
|
+
a design decision. Exported rather than repeated, because the next component to
|
|
149
|
+
wear the panel has to make the same subtraction and will not think to.
|
|
150
|
+
|
|
151
|
+
It renders above the pager. The two answer different questions and both belong
|
|
152
|
+
there: this is the semantic answer, the pager the linear one.
|
|
153
|
+
|
|
154
|
+
A real `<h2>` names it, not an `aria-label` — a reader moving by heading would
|
|
155
|
+
pass straight over a region named only by an attribute.
|
|
156
|
+
|
|
157
|
+
## The key is `explore`, and neither `next` nor `steps` would do
|
|
158
|
+
|
|
159
|
+
`next` is unusable in this package. `src/next.ts` is the Next.js adapter, so
|
|
160
|
+
two files one directory apart would carry the same name for entirely different
|
|
161
|
+
things, and `doc.frontmatter.next` would read like a routing hook rather than
|
|
162
|
+
a block of prose.
|
|
163
|
+
|
|
164
|
+
`steps` is wrong for a different reason: these rows are a _branch_, not a
|
|
165
|
+
sequence. A reader picks one and ignores the rest, and none of them is first.
|
|
166
|
+
A numbered "1 -> 2 -> 3" component is a real and separate thing worth building
|
|
167
|
+
later, and `steps` is the name it will need.
|
|
168
|
+
|
|
169
|
+
The rendered heading is still "Where to go next" — `next` in prose is fine,
|
|
170
|
+
it is only the identifier that had to move.
|
|
171
|
+
|
|
172
|
+
No client JavaScript. New: `DocsExplore` at `@waveso/docs/react/explore`,
|
|
173
|
+
`explore` in frontmatter, and `explore` in `labels`.
|
|
174
|
+
|
|
175
|
+
- c871d2f: **One radius scale, taken from `@waveso/ui`, retunable from a single line.**
|
|
176
|
+
|
|
177
|
+
Three tiers, all `calc()` off one root, so which corner a box gets is decided by
|
|
178
|
+
what _kind_ of box it is rather than by how big it happens to be:
|
|
179
|
+
|
|
180
|
+
| Token | What takes it |
|
|
181
|
+
| ----------------------- | ----------------------------------------------------------- |
|
|
182
|
+
| `--wave-docs-radius-sm` | inline chips, small controls, focus rings on those |
|
|
183
|
+
| `--wave-docs-radius` | controls, overlays, and the panel's inset surface |
|
|
184
|
+
| `--wave-docs-radius-lg` | every block in the reading flow, and the panel's outer edge |
|
|
185
|
+
|
|
186
|
+
⚠️ THE BLOCK TIER WAS SPLIT. Callouts, images and video embeds sat at the base
|
|
187
|
+
radius while a code frame and a table sat at 19px, so two blocks a paragraph
|
|
188
|
+
apart disagreed by eleven pixels — and a table read as aggressively round next
|
|
189
|
+
to the callout above it. 19 was measured off a reference site, which is a fine
|
|
190
|
+
way to pick a number and a bad way to pick a _system_.
|
|
191
|
+
|
|
192
|
+
⚠️ AND THE NUMBERS ARE `@waveso/ui`'s, NOT NEW ONES. A page running both this
|
|
193
|
+
package and the component library should not show two radius scales a few pixels
|
|
194
|
+
apart, and taking theirs is how that is guaranteed rather than kept in step by
|
|
195
|
+
hand. `--wave-docs-radius-base` is the override point: a host writes
|
|
196
|
+
`--wave-docs-radius-base: var(--radius)` and every corner here follows their app,
|
|
197
|
+
including any theme that moves it. Overriding three tokens separately would be
|
|
198
|
+
three chances to break the arithmetic below.
|
|
199
|
+
|
|
200
|
+
⚠️ `--wave-docs-radius-step` IS LOAD-BEARING. The panel's inset surface takes the
|
|
201
|
+
base radius and its frame takes `-lg`, which is the base plus one step — so the
|
|
202
|
+
two corners are concentric only while the frame's _padding_ is that same step.
|
|
203
|
+
It is paid out of the token rather than written as `4px`, so moving the root
|
|
204
|
+
keeps both true. `--wave-docs-radius-panel` is gone with it: a token whose only
|
|
205
|
+
job is to be another token minus a constant is a number that can drift from its
|
|
206
|
+
own definition.
|
|
207
|
+
|
|
208
|
+
## Squircles, where the browser has them
|
|
209
|
+
|
|
210
|
+
`corner-shape` renders every `border-radius` as a continuous superellipse rather
|
|
211
|
+
than a circular arc. `@waveso/ui` ships it and this now matches, including the
|
|
212
|
+
root bump both make under the same `@supports` — a squircle reads tighter at the
|
|
213
|
+
same radius, so the scale moves up to restore the roundness the numbers were
|
|
214
|
+
chosen for. Only the root moves; every tier and the panel's padding follow.
|
|
215
|
+
|
|
216
|
+
⚠️ SCOPED TO ELEMENTS THIS PACKAGE OWNS, AND NOT `*`. `@waveso/ui` can say `*`
|
|
217
|
+
because it is the application's own stylesheet. This one is mounted inside
|
|
218
|
+
somebody else's page, and a bare `*` would reshape every corner the host drew —
|
|
219
|
+
the same trespass as claiming `html` or `body`, which this file already refuses.
|
|
220
|
+
Pills and dots opt back out, because a squircled pill is a lozenge.
|
|
221
|
+
|
|
222
|
+
⚠️ AND THE SOURCE TEST FOR THE CONCENTRIC ARITHMETIC WENT VACUOUS ON THE WAY.
|
|
223
|
+
It regexed three `rem` literals out of the token block; with the tiers as
|
|
224
|
+
`calc()` the regex matched nothing, both sides defaulted to zero, and `0 - 0`
|
|
225
|
+
passed while asserting nothing. It is measured in computed pixels now, which is
|
|
226
|
+
also the only tier that can see the squircle bump. Two browser assertions that
|
|
227
|
+
built an expected radius out of `getPropertyValue` were the same mistake in a
|
|
228
|
+
different shape — a custom property is not computed to pixels, so it hands back
|
|
229
|
+
the `calc()` as written. They compare two computed corners to each other now,
|
|
230
|
+
which is the uniformity claim anyway.
|
|
231
|
+
|
|
232
|
+
### Patch Changes
|
|
233
|
+
|
|
234
|
+
- 04b7de7: **A blockquote is a box, not a rule down one edge.**
|
|
235
|
+
|
|
236
|
+
Every other block set apart from the prose here — a callout, a code frame, a
|
|
237
|
+
table, an embed — is a bordered box. A single 3px edge made the quote the one
|
|
238
|
+
exception, so next to a callout two paragraphs away it read as a _different kind
|
|
239
|
+
of thing_ rather than as a quieter one.
|
|
240
|
+
|
|
241
|
+
It is the callout's box now, minus the hue: the same padding so their text lines
|
|
242
|
+
up, the same block radius, a plain border instead of a tinted one, and no accent
|
|
243
|
+
edge. That is the relationship — **a callout is a quote with a colour** — and it
|
|
244
|
+
finally looks like it.
|
|
245
|
+
|
|
246
|
+
Still not italic. The box and the muted colour already say "quotation", a long
|
|
247
|
+
italic passage is measurably slower to read, and markdown authors use
|
|
248
|
+
blockquotes for asides and notes rather than only for speech.
|
|
249
|
+
|
|
250
|
+
⚠️ AND IT HAD TO JOIN THE SQUIRCLE LIST BY NAME. Corner shaping is scoped to
|
|
251
|
+
elements this package owns, matched by our own class prefix — and a `blockquote`
|
|
252
|
+
is the markdown author's tag, with no class of ours on it. It would have been
|
|
253
|
+
the one block on the page still drawing a circular arc.
|
|
254
|
+
|
|
255
|
+
- 975acba: **A callout draws one uniform border, not a 3px rule down its inline start.**
|
|
256
|
+
|
|
257
|
+
The stripe made a callout the exception among blocks set apart from the prose —
|
|
258
|
+
a code frame, a table, an embed and now a blockquote are all boxes with one
|
|
259
|
+
border all the way round — so beside any of them it read as a different kind of
|
|
260
|
+
thing rather than as a coloured one. A thick rule on one side also fights the
|
|
261
|
+
corner it runs into once the box is a squircle.
|
|
262
|
+
|
|
263
|
+
⚠️ THE TYPE IS STILL NOT CONVEYED BY COLOUR ALONE. The stripe was never what
|
|
264
|
+
carried it: the icon and the label — "Note", "Warning" — are the non-colour
|
|
265
|
+
signals, and they are unchanged. The tinted border and ground stay as
|
|
266
|
+
reinforcement rather than as the whole message.
|
|
267
|
+
|
|
268
|
+
The table-of-contents rail keeps its 2px inline-start border. That is a
|
|
269
|
+
continuous line an active marker slides along, which is a navigation affordance
|
|
270
|
+
rather than the edge of a box, and a source guard names the two blocks it does
|
|
271
|
+
apply to.
|
|
272
|
+
|
|
273
|
+
- cd21631: **The copy button draws Lucide icons, like everything else here.**
|
|
274
|
+
|
|
275
|
+
It rendered `⧉`, and swapped in `✓` and `×` through CSS `content` — three
|
|
276
|
+
characters drawn by whatever font resolved, at whatever weight and baseline
|
|
277
|
+
that font has, beside a sidebar, a pager, a callout and a search dialog that
|
|
278
|
+
are all Lucide paths at `stroke-width: 2`. It read as a different icon set
|
|
279
|
+
because it was one. Now `copy`, `check` and `x` on the same 24×24 grid.
|
|
280
|
+
|
|
281
|
+
⚠️ THE SWAP IS `display` AND NOT `visibility`, AND THAT IS NOT A PREFERENCE.
|
|
282
|
+
All three icons ship in the markup and the stylesheet picks one — there is no
|
|
283
|
+
component owning this button, so there is no state to re-render. But the button
|
|
284
|
+
is `visibility: hidden` until the runtime attaches, which is what keeps a reader
|
|
285
|
+
with no JavaScript from meeting a control that does nothing and keeps it out of
|
|
286
|
+
the tab order — and `visibility` inherits. An icon rule setting it back to
|
|
287
|
+
`visible` would draw a glyph inside a button that is meant to be invisible.
|
|
288
|
+
`display` does not inherit, so the button's own rule still governs all three.
|
|
289
|
+
|
|
290
|
+
Three icons per fence is fifty on a page with fifty of them, and the repeat is
|
|
291
|
+
why that is affordable: byte-identical every time, which is the case gzip
|
|
292
|
+
handles best. The quick start's gzipped payload did not move, and the
|
|
293
|
+
hast-over-the-wire ratio for code and tables went from 1.11× to 1.09×.
|
|
294
|
+
|
|
295
|
+
## And it stops drawing a box around itself
|
|
296
|
+
|
|
297
|
+
No border and no ground, in any state. A bordered, filled 2rem box sitting on
|
|
298
|
+
the frame's own band is a third framed rectangle inside a frame that already has
|
|
299
|
+
two, for a control secondary to everything around it. The glyph is the whole
|
|
300
|
+
control, and hover moves its ink to the accent rather than putting a box behind
|
|
301
|
+
it — the same signal every other interactive surface here gives. A ground also
|
|
302
|
+
had nowhere to come from: the subtle ramp _is_ the frame's colour, so the hover
|
|
303
|
+
state it used to have was the colour the button was already sitting on.
|
|
304
|
+
|
|
305
|
+
⚠️ AND IT HAD NO FOCUS INDICATOR AT ALL, WHICH THE BORDER WAS COVERING FOR. A
|
|
306
|
+
1px box is not a focus indicator — it is there whether the control is focused or
|
|
307
|
+
not — so a keyboard reader tabbing onto this button got a `color` change and
|
|
308
|
+
nothing else, and it never appeared in the package's own inventory of focusable
|
|
309
|
+
surfaces. Taking the border away made that visible; it did not create it. There
|
|
310
|
+
is a real `:focus-visible` outline now, and a test that keeps it.
|
|
311
|
+
|
|
312
|
+
⚠️ AND ONE TEST WAS PASSING BY ACCIDENT. `render.test.ts` asserted that a
|
|
313
|
+
GitHub alert produces no octicons by checking the _whole document_ for `<svg>`,
|
|
314
|
+
which was only ever true because nothing else in the pipeline emitted one. It
|
|
315
|
+
now checks the callout's own subtree, which is what it meant.
|
|
316
|
+
|
|
317
|
+
- d7333cb: **The site's pages stop hand-writing their own "Next" link.** Nineteen of them
|
|
318
|
+
ended with `Next: [Page](./page.md).`, which the pager has rendered from the
|
|
319
|
+
navigation tree since it landed — the same link, twice, a few hundred pixels
|
|
320
|
+
apart, and the hand-written one silently wrong the moment a page moved in the
|
|
321
|
+
tree.
|
|
322
|
+
|
|
323
|
+
Documentation-only: no package change.
|
|
324
|
+
|
|
325
|
+
- 6f0afb7: **A panel title is the size of a column header.**
|
|
326
|
+
|
|
327
|
+
"Where to go next" and `Enforced by` are the same kind of thing — the label a
|
|
328
|
+
reader's eye lands on before the content under it — and a page shows both. At
|
|
329
|
+
`0.875rem` against the table's `0.9375rem` they read as two levels rather than
|
|
330
|
+
as one.
|
|
331
|
+
|
|
332
|
+
The weight does not follow: a panel title names the block, a column header names
|
|
333
|
+
a column inside one, so the title stays a step heavier. A source guard pins the
|
|
334
|
+
pair, because two literals that have to agree are two literals that drift.
|
|
335
|
+
|
|
336
|
+
- 8c59155: The navigation stops being lopsided.
|
|
337
|
+
|
|
338
|
+
Its rows sat 16px from the inline start and 31px from the end. The 15px was
|
|
339
|
+
`scrollbar-gutter: stable`, which reserves the scrollbar's width whether or not
|
|
340
|
+
it is showing — and that reservation sits _inside_ the padding.
|
|
341
|
+
|
|
342
|
+
The jump it prevents is one 15px shift, the first time a nav grows past a
|
|
343
|
+
screen. What it cost was permanent and on every page.
|
|
344
|
+
|
|
345
|
+
⚠️ AND IT IS A NO-OP ON macOS, WHICH IS WHY IT SURVIVED BEING LOOKED AT.
|
|
346
|
+
`scrollbar-gutter` does nothing where overlay scrollbars are the default, so the
|
|
347
|
+
asymmetry was invisible to everyone who built this and plain on every Windows
|
|
348
|
+
and Linux machine that opened it.
|
|
349
|
+
|
|
350
|
+
`scrollbar-width: thin` in its place, with `scrollbar-color`, so the scrollbar
|
|
351
|
+
that does appear is narrow and coloured rather than a UA slab against the
|
|
352
|
+
panel's edge. A browser test measures both insets and fails at 15px.
|
|
353
|
+
|
|
354
|
+
- e94bb67: **A table keeps one frame, at the panel's radius.**
|
|
355
|
+
|
|
356
|
+
It wore `.wave-docs-panel` for a while — outer frame, header band, inset card —
|
|
357
|
+
and that was wrong for a reason worth writing down rather than just undoing.
|
|
358
|
+
|
|
359
|
+
⚠️ THE PANEL SEPARATES _CHROME_ FROM _CONTENT_, AND A TABLE'S HEADER ROW IS
|
|
360
|
+
CONTENT. "Where to go next" and a code frame both have chrome to put in the
|
|
361
|
+
band: a title, a language, a copy button. A table's `<thead>` is data. Setting
|
|
362
|
+
the body into a card away from its own header cost three vertical rules down
|
|
363
|
+
each side, stopped the row dividers short of the box and narrowed the reading
|
|
364
|
+
width — on the densest element on a page, for nothing gained. Full-width
|
|
365
|
+
dividers are what let an eye track a row across.
|
|
366
|
+
|
|
367
|
+
What is kept is the outer radius: `--wave-docs-radius-lg` rather than
|
|
368
|
+
`--wave-docs-radius`, so a table and a code block read as two of one family
|
|
369
|
+
without the table pretending to chrome it has not got.
|
|
370
|
+
|
|
371
|
+
⚠️ AND AN EMPTY HEADER ROW NOW DRAWS NO BAND, WHICH GFM PRODUCES ROUTINELY. A
|
|
372
|
+
GFM table always has a `<thead>` — the delimiter row is what makes it a table —
|
|
373
|
+
so an author who wants a plain two-column list of facts writes `| | |` and gets
|
|
374
|
+
a header of empty `<th>`s, which rendered as a tinted strip with nothing in it.
|
|
375
|
+
`:empty` and not a text check: GFM emits `<th></th>` with no whitespace inside.
|
|
376
|
+
A header with even one named column keeps its band.
|
|
377
|
+
|
|
378
|
+
**And a fence with neither a title nor a language gets no band either.** The
|
|
379
|
+
header row is floored so titled and untitled fences match, which is right when
|
|
380
|
+
there is a label and wrong when there is not: a bare fence had only the copy
|
|
381
|
+
button, adrift in a strip of empty ground. The row is the button now.
|
|
382
|
+
|
|
383
|
+
## 0.10.0
|
|
384
|
+
|
|
385
|
+
### Minor Changes
|
|
386
|
+
|
|
387
|
+
- f52cb99: **Every page links to the ones either side of it.** `docs.Page` renders a pager
|
|
388
|
+
under the prose. Nothing is authored: a page gets one by being in the
|
|
389
|
+
navigation.
|
|
390
|
+
|
|
391
|
+
⚠️ THE ORDER IS THE SIDEBAR'S, NOT THE SLUG LIST'S. `generateStaticParams` has
|
|
392
|
+
every route in it and no opinion about their order; `meta.json` is where the
|
|
393
|
+
author said what comes next, and it is what the reader is looking at. Two
|
|
394
|
+
orderings of the same pages is two answers to one question, and they drift the
|
|
395
|
+
first time a `meta.json` moves — so the pager reads the same tree `DocsSidebar`
|
|
396
|
+
renders and flattens it. A pager that disagrees with the column beside it is
|
|
397
|
+
impossible by construction.
|
|
398
|
+
|
|
399
|
+
Separators and external links are not stops: a separator is a label with
|
|
400
|
+
nowhere to go, and a "next page" that lands on npm has ended the sequence
|
|
401
|
+
rather than continued it. A group with an `index.md` contributes its own page
|
|
402
|
+
before its children, which is the order its rows appear in.
|
|
403
|
+
|
|
404
|
+
⚠️ A PAGE OUTSIDE THE TREE GETS NO PAGER, RATHER THAN THE FIRST ONE. `-1` from
|
|
405
|
+
`findIndex` reads as "just before the beginning", so an unguarded lookup hands
|
|
406
|
+
every draft and every route rendered outside the navigation the same first page
|
|
407
|
+
as its "next" — confidently wrong on exactly the pages nobody checks.
|
|
408
|
+
|
|
409
|
+
⚠️ AND AN EMPTY CELL AT EACH END, NOT A MISSING ONE. The two links share a grid
|
|
410
|
+
row; drop the absent side and the survivor slides into the first track, so the
|
|
411
|
+
first page of a site puts "Next" on the left and every other page puts it on
|
|
412
|
+
the right. The one page where the position moves is the one a reader sees
|
|
413
|
+
first.
|
|
414
|
+
|
|
415
|
+
Nothing renders at all when there is no neighbour either side — a one-page site
|
|
416
|
+
would otherwise get a navigation landmark containing nothing.
|
|
417
|
+
|
|
418
|
+
A chevron on the outer edge of each link points the way it goes.
|
|
419
|
+
|
|
420
|
+
⚠️ AND "OUTWARD" MIRRORS. Under `dir="rtl"` the grid's first track is on the
|
|
421
|
+
right, so the _previous_ link moves there and its arrow has to point right —
|
|
422
|
+
the reverse of the rule that draws it. Same trap as the sidebar's chevron, in a
|
|
423
|
+
component built after it, and `[dir='rtl']` again rather than `:dir(rtl)`.
|
|
424
|
+
|
|
425
|
+
No client JavaScript: two links, two captions and two glyphs, rendered on the
|
|
426
|
+
server. Each
|
|
427
|
+
link is named by direction _and_ destination — "Previous: Installation" — since
|
|
428
|
+
a link announced as a bare title says nothing about which way it goes. The
|
|
429
|
+
landmark is named too, because a page now carries three of them.
|
|
430
|
+
|
|
431
|
+
New: `DocsPager` at `@waveso/docs/react/pager`, `pager: false` on
|
|
432
|
+
`createDocsRoute` to omit it, and `previousPage`, `nextPage` and `pagination`
|
|
433
|
+
in `labels`.
|
|
434
|
+
|
|
435
|
+
### Patch Changes
|
|
436
|
+
|
|
437
|
+
- 09a9369: The sidebar grip says whether it has anything to do.
|
|
438
|
+
|
|
439
|
+
Blue when the navigation is hidden or the pointer is on it; grey when the
|
|
440
|
+
sidebar is open and untouched. One rule at every width — a closed sidebar is
|
|
441
|
+
the same request for attention on a phone as on a desktop.
|
|
442
|
+
|
|
443
|
+
⚠️ `:not([data-state='open'])`, NOT `[data-state='closed']`. The attribute is
|
|
444
|
+
absent until the reader chooses, and a server-rendered page has none — so
|
|
445
|
+
matching only the explicit value leaves every first paint below 64rem showing a
|
|
446
|
+
grey grip in front of hidden navigation, which is the one moment the cue is
|
|
447
|
+
for. Above 64rem the default inverts, and a second rule says so.
|
|
448
|
+
|
|
449
|
+
⚠️ AND THE COLOUR IS A CUSTOM PROPERTY, NOT A SELECTOR FIGHT. Three things want
|
|
450
|
+
to set it — the resting style, the pointer, and the sidebar's state — and the
|
|
451
|
+
state lives on an _ancestor_, so `.sidebar[data-state] .trigger::before`
|
|
452
|
+
outranks `.trigger:hover::before` by a whole class. Written as backgrounds that
|
|
453
|
+
is a rule which silently kills hover on the one state that still needs it.
|
|
454
|
+
Properties settle it by inheritance: the state sets them on the sidebar, the
|
|
455
|
+
trigger sets them on itself under `:hover`, and a value on the element always
|
|
456
|
+
beats one it inherited. No specificity ladder, no `!important`.
|
|
457
|
+
|
|
458
|
+
The grip is also a full pill now rather than a rounded rectangle.
|
|
459
|
+
|
|
460
|
+
⚠️ TESTED AS MARKUP, BECAUSE A MOUNTED COMPONENT CANNOT SHOW THE UNTOUCHED
|
|
461
|
+
STATE. `DocsNav` resolves the mode on mount and writes `data-state`
|
|
462
|
+
immediately, so every React fixture is already explicit. Two wrong versions
|
|
463
|
+
passed the whole suite against that — matching the explicit value, and dropping
|
|
464
|
+
the wide-layout reset — and both are caught now by a server-shaped fixture with
|
|
465
|
+
no attribute at all.
|
|
466
|
+
|
|
467
|
+
Also fixed here: the focus-indicator guard looked up one rule per selector, and
|
|
468
|
+
a selector may legitimately appear in several. The trigger now has one rule
|
|
469
|
+
setting properties on focus and another drawing the ring; taking "the first" or
|
|
470
|
+
"the last" is a coin flip on file order, so it reads every rule and asks for
|
|
471
|
+
one to declare an outline.
|
|
472
|
+
|
|
473
|
+
## 0.9.2
|
|
474
|
+
|
|
475
|
+
### Patch Changes
|
|
476
|
+
|
|
477
|
+
- 6b84354: A separator now rules off the block above it.
|
|
478
|
+
|
|
479
|
+
It ends one section as much as it names the next, and 1rem of margin was not
|
|
480
|
+
saying so — the gap read as "these two lists are a bit far apart" rather than as
|
|
481
|
+
a division.
|
|
482
|
+
|
|
483
|
+
⚠️ THE RULE AND THE LABEL SHARE THE LIST'S OWN EDGE, WHICH IS ALSO THE ROWS'. A
|
|
484
|
+
row is full-bleed — its hover surface spans the whole column, and so does the
|
|
485
|
+
search field above it — so a rule on that edge divides the column, while an
|
|
486
|
+
inset one floats inside it. The label sits on the same line, because a heading
|
|
487
|
+
and the rule above it reading as one object is the whole reason the rule exists.
|
|
488
|
+
|
|
489
|
+
The label keeps the rows' own content edge — the marker column when there is
|
|
490
|
+
one, the words when `icons={false}` removes it. Those are the same number: a
|
|
491
|
+
row's `padding-inline` is what both modes have in common, so matching it lands
|
|
492
|
+
on whichever is there, with no query and nothing threaded to the stylesheet.
|
|
493
|
+
|
|
494
|
+
⚠️ AND NOT ABOVE THE FIRST CHILD. A `meta.json` may open with
|
|
495
|
+
`"---Reference---"`, and on that tree the very first thing in the navigation
|
|
496
|
+
would otherwise be a hairline above nothing.
|
|
497
|
+
|
|
498
|
+
The label also drops from `font-weight: 650` to `500`. At 650 it was heavier
|
|
499
|
+
than the group titles it sits under — a divider out-shouting the navigation it
|
|
500
|
+
divides. Weight rather than colour, because there is no lighter colour to
|
|
501
|
+
reach for: `--wave-docs-fg-subtle` is already the lightest text token at 5.05:1
|
|
502
|
+
against WCAG 1.4.3's 4.5:1 floor, and `--wave-docs-border` — the rule's own
|
|
503
|
+
colour — measures 1.31:1 and is a line colour, not a text one.
|
|
504
|
+
|
|
505
|
+
- 7e67c5a: The table of contents marks the last section when you reach it.
|
|
506
|
+
|
|
507
|
+
Scroll to the foot of a page whose final section is short and nothing happened:
|
|
508
|
+
the entry stayed on the section _above_, and the last one could only be
|
|
509
|
+
highlighted by clicking its own link.
|
|
510
|
+
|
|
511
|
+
⚠️ NO `rootMargin` FIXES THIS, WHICH IS WHY IT LOOKED LIKE A TUNING PROBLEM.
|
|
512
|
+
The default makes the top 40% of the viewport the region that counts as
|
|
513
|
+
current, and that is right while there is document left to scroll — a heading
|
|
514
|
+
rises into the band and takes the highlight. At the end there is none. A short
|
|
515
|
+
trailing section sits on screen, fully readable, below a band it can never
|
|
516
|
+
enter, while the heading above it is still _inside_ that band. The observer was
|
|
517
|
+
giving a correct answer to the wrong question. Any band smaller than the
|
|
518
|
+
viewport has this hole; a bigger one only trades it for a highlight that jumps
|
|
519
|
+
early.
|
|
520
|
+
|
|
521
|
+
So the end of the document is handled as what it is — a place where scrolling
|
|
522
|
+
stops answering — and the last heading takes the highlight there. Scroll up and
|
|
523
|
+
the band has it straight back, without waiting for a heading to cross.
|
|
524
|
+
|
|
525
|
+
⚠️ AND BOTH INPUTS GO THROUGH ONE RESOLVER, WHICH IS THE HALF THAT IS EASY TO
|
|
526
|
+
MISS. Left as two `setActiveId` calls they race, and the observer wins — it
|
|
527
|
+
fires last and it still likes the heading above. The first version of this fix
|
|
528
|
+
was measured doing exactly nothing for that reason.
|
|
529
|
+
|
|
530
|
+
⚠️ ONLY WHEN THE DOCUMENT ACTUALLY SCROLLS. On a page that fits, "scrolled to
|
|
531
|
+
the bottom" is true at rest, and the last section would be current before the
|
|
532
|
+
reader had read a word of the first.
|
|
533
|
+
|
|
534
|
+
The listener is `passive` and reads two numbers — no `getBoundingClientRect`,
|
|
535
|
+
no layout flush. Like every other scroll reader here it watches the document; a
|
|
536
|
+
host that scrolls an inner pane keeps the observer's behaviour and loses only
|
|
537
|
+
this tail case.
|
|
538
|
+
|
|
539
|
+
`toc` grows 0.88 → 1 KB, and the published total 14.5 → 14.6 KB. It is still
|
|
540
|
+
the smallest client component in the package.
|
|
541
|
+
|
|
3
542
|
## 0.9.1
|
|
4
543
|
|
|
5
544
|
### Patch Changes
|