@jsenv/navi 0.29.235 → 0.29.238

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.
@@ -191,9 +191,11 @@ to start when unsure which export solves a problem.
191
191
 
192
192
  - `css_architecture.md` — navi wins by default, defaults sit in `@layer navi`,
193
193
  props first; `--navi-*` versus `--component-*`; what a popup inherits from its
194
- opener; `import.meta.css` and what a `${}` costs; browsers are the consuming
195
- app's target. Read before overriding a component style, and before any
196
- `import.meta.css`.
194
+ opener; a popup and a callout are element children your `:last-child` counts;
195
+ `import.meta.css` and what a `${}` costs; browsers are the consuming app's
196
+ target. Read before overriding a component style, before any
197
+ `import.meta.css`, and before a structural selector (`:last-child`,
198
+ `:nth-child`, `:empty`) on a container holding navi components.
197
199
  - `safe_area.md` — the two inset families, an app narrower than the window
198
200
  (`--navi-app-max-width`), `data-navi-safe-area`, which viewport is which under
199
201
  a virtual keyboard. Read before hand-writing an offset to clear a `FixedBar`.
@@ -13,6 +13,8 @@
13
13
  - [1. Component props (preferred)](#1-component-props-preferred)
14
14
  - [2. CSS variables (for global or theme-level changes)](#2-css-variables-for-global-or-theme-level-changes)
15
15
  - [3. Direct rule override (avoid unless necessary)](#3-direct-rule-override-avoid-unless-necessary)
16
+ - [Counting children: what navi puts in your tree](#counting-children-what-navi-puts-in-your-tree)
17
+ - [Say which children the rule means](#say-which-children-the-rule-means)
16
18
  - [Summary](#summary)
17
19
 
18
20
  ## Overview
@@ -97,7 +99,9 @@ just its line, and the stylesheet then ships verbatim: comments and whitespace
97
99
  included, nothing transpiled for the browsers the app targets (nesting,
98
100
  `light-dark()`, `color-mix()` reach them as written), a `url("./icon.svg")`
99
101
  neither copied nor hashed and resolved against the document — a silent 404 in
100
- production — nothing checked, nothing minified. And nothing is logged.
102
+ production — nothing checked, nothing minified. The build warns about it; a css comment
103
+ containing `jsenv-css-opaque` inside the template silences that one template when there
104
+ is no way around it.
101
105
 
102
106
  The one substitution the build reads stands exactly **where a css value
103
107
  stands** — inside a rule block, after the `:` of a declaration, not in a string,
@@ -476,15 +480,85 @@ Overriding the actual CSS rules (not the variables) is intentionally hard — th
476
480
 
477
481
  ---
478
482
 
483
+ ## Counting children: what navi puts in your tree
484
+
485
+ Some of what navi shows is rendered inside the tree you wrote. A popup renders
486
+ in its opener's own subtree, so a `Dialog` or `Popover` written next to the
487
+ button that opens it is a sibling of that button. A callout — the speech bubble
488
+ a control pops to explain itself — is mounted on what it explains, or beside it
489
+ when that element cannot hold it (a `<button>`, an `<input>`, anything inside a
490
+ `<label>`). This is deliberate: they inherit your fonts, your colors, your
491
+ custom properties, and they leave with the screen that opened them.
492
+
493
+ None of them draws in the flow. They are `position: fixed`/`absolute`, most of
494
+ them in the top layer: no grid track, no flex item, no line box, no gap. They
495
+ move nothing.
496
+
497
+ **But they are element children, and structural selectors count element
498
+ children.** `:last-child`, `:first-child`, `:nth-child`, `:nth-last-child`,
499
+ `:only-child`, `:empty`, `> * + *` look at the element tree — never at
500
+ `display`, `position`, or the top layer, and CSS offers no exception for
501
+ out-of-flow elements. So a rule of yours that depends on the number or the
502
+ order of children stops matching for exactly as long as a popup or a callout is
503
+ open:
504
+
505
+ ```css
506
+ /* three cells in a two-column grid, the odd last one spanning both */
507
+ .grid > .cell:last-child:nth-child(odd) {
508
+ grid-column: 1 / -1;
509
+ }
510
+ ```
511
+
512
+ Press the third cell, its callout opens, and the cell is no longer the last
513
+ child: it loses the span and halves. Close the callout and it comes back. The
514
+ grid reserved nothing — the rule simply stopped matching. What makes this one
515
+ nasty is that it is invisible from the app: the CSS is right, the JSX is right,
516
+ and the trap only springs on an interaction, after the layout was reviewed.
517
+
518
+ ### Say which children the rule means
519
+
520
+ A counting pseudo-class takes what to count: `:nth-child(An+B of S)` and
521
+ `:nth-last-child(An+B of S)` walk only the children matching `S`, so name your
522
+ own — either by what they are, or by what navi's out-of-flow elements all carry
523
+ (`navi-out-of-flow`, the same marker navi's own `Group` reads):
524
+
525
+ ```css
526
+ .grid > .cell:nth-last-child(1 of .cell):nth-child(odd of .cell) {
527
+ grid-column: 1 / -1;
528
+ }
529
+ ```
530
+
531
+ `:last-child` and `:first-child` take no such argument — spell them
532
+ `:nth-last-child(1 of S)` and `:nth-child(1 of S)` when you need one. A sibling
533
+ combinator is the other shape, and there the marker goes between the compounds:
534
+
535
+ ```css
536
+ .stack > *:not([navi-out-of-flow]) + *:not([navi-out-of-flow]) {
537
+ margin-block-start: 8px;
538
+ }
539
+ ```
540
+
541
+ The third way is to stop asking a structural question at all: put a class on the
542
+ cell you mean and style that. It is the most robust of the three — it survives
543
+ anything else landing in that container later.
544
+
545
+ In dev, navi warns when opening a callout moves the element it is anchored on,
546
+ or that element's container: a callout has no layout box, so anything moving
547
+ means a rule like the one above just changed subject. The warning names both
548
+ elements and the boxes before and after.
549
+
550
+ ---
551
+
479
552
  ## Summary
480
553
 
481
- | What you want to change | How to do it |
482
- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
483
- | One component instance | Component prop or `style` attribute |
484
- | All instances of a component | `--component-*` in unlayered app CSS, on a selector matching the component |
485
- | A global design token | `--navi-*` on `:root` |
486
- | The share of ink in `secondary`/`emphasis`/`discrete`/`hint` | `--navi-color-*-mix` on `:root` — never on a container |
487
- | A container's own paper (a dark card) | `color` on the container, plus a `--navi-color-*` keyword pinned if its formula reads wrong there; both stop at the next popup |
488
- | How wide popups may ever get | `--navi-app-max-width` on `:root` |
489
- | A structural layout rule | Expose a new CSS variable (contribute) |
490
- | What a variant decided | A prop — a variant only ever moves defaults, so props keep winning |
554
+ | What you want to change | How to do it |
555
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
556
+ | One component instance | Component prop or `style` attribute |
557
+ | All instances of a component | `--component-*` in unlayered app CSS, on a selector matching the component |
558
+ | A global design token | `--navi-*` on `:root` |
559
+ | The share of ink in `secondary`/`emphasis`/`discrete`/`hint` | `--navi-color-*-mix` on `:root` — never on a container |
560
+ | A container's own paper (a dark card) | `color` on the container, plus a `--navi-color-*` keyword pinned if its formula reads wrong there; both stop at the next popup |
561
+ | How wide popups may ever get | `--navi-app-max-width` on `:root` |
562
+ | A structural layout rule | Expose a new CSS variable (contribute) |
563
+ | A rule counting children of a container holding navi controls | `:nth-child(… of S)`, `:not([navi-out-of-flow])`, or a class — a popup or a callout is a child too |
564
+ | What a variant decided | A prop — a variant only ever moves defaults, so props keep winning |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.29.235",
3
+ "version": "0.29.238",
4
4
  "type": "module",
5
5
  "description": "Library of components including navigation to create frontend applications",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@preact/signals": "^2.11.2",
34
- "preact": "^11.0.0-beta.2"
34
+ "preact": "^11.0.0-rc.2"
35
35
  },
36
36
  "dependencies": {
37
37
  "@jsenv/dom": "0.17.61",
@@ -47,8 +47,8 @@
47
47
  "@jsenv/terminal-table": "../../tooling/terminal-table",
48
48
  "@jsenv/urls": "../../tooling/urls",
49
49
  "@preact/signals": "2.11.2",
50
- "playwright": "1.62.1",
51
- "preact": "11.0.0-beta.2"
50
+ "playwright": "1.63.0",
51
+ "preact": "11.0.0-rc.2"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"