@nxgt/material 3.7.2 → 3.7.4

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.
@@ -81,7 +81,7 @@ phone's menu sheet pad clear of `env(safe-area-inset-*)`, as classes; see the
81
81
  | `titleAs` | `'h1'` … `'h6'` \| `'div'` | `'h1'` | `ActivityContent`: the title's heading level |
82
82
  | `inset` | `boolean` | `false` | `ActivityContent`: pads the content 1rem on each side. Off, it lines up with the app bar and the cards |
83
83
  | `align` | `'start' \| 'center'` | `'start'` | `ActivityLayout`, `AppSidebar`: the collapsed rail's entries sit right under the brand, or `'center'` for centred in the height below it |
84
- | `backdrop` | `ReactNode` | — | `ActivityLayout`: a decorative background behind the frame, in place of the gradient and its blobs: a `Background` preset from `@nxgt/material/backgrounds`. Rendered in an `inert`, `aria-hidden` layer that fills the content column; the chrome and lists stay opaque over it, coloured by `--nxgt-backdrop-chrome` and `--nxgt-backdrop-surface`. See [Use a background preset behind the shell](../guides/app-shell.md#use-a-background-preset-behind-the-shell) |
84
+ | `backdrop` | `ReactNode` | — | `ActivityLayout`: a decorative background behind the frame, in place of the gradient and its blobs: a `Background` preset from `@nxgt/material/backgrounds`. Rendered in an `inert`, `aria-hidden` layer as wide as the content column and one viewport high, fixed in the viewport while the content scrolls; the chrome (app bar, breadcrumb, tabs strip) is lightly translucent and frosted over it (80%, 87% for the sidebar, breadcrumb and tabs strip, 92% and no blur under `prefers-reduced-transparency` or without `backdrop-filter`), and the lists, tables and cards stay opaque; `--nxgt-backdrop-chrome` sets the chrome's fill and `--nxgt-backdrop-surface` the lists'. See [Use a background preset behind the shell](../guides/app-shell.md#use-a-background-preset-behind-the-shell) |
85
85
  | `routeTransition` | `boolean \| Omit<ViewTransitionProps, 'children' \| 'ref'>` | `true` | `ActivityLayout`: React's `<ViewTransition>` around the content region, so a navigation cross-fades it. `false` renders none (your app has its own boundary); an object passes `default` / `update` classes, `name`, callbacks through. See [Route transitions](../guides/app-shell.md#route-transitions) |
86
86
 
87
87
  The active entry is the longest match across the whole menu, segment-aware.
@@ -513,26 +513,29 @@ export function Shell({ items }: { items: MenuItem[] }) {
513
513
  CSS, no inline `style`). Without it the markup and the look are what they
514
514
  were; `null`, `undefined` and `false` count as none.
515
515
  - **It sits behind the content column.** The node is wrapped in a layer
516
- (`[data-slot="activity-layout-backdrop"]`) that fills the column beside the
516
+ (`[data-slot="activity-layout-backdrop"]`) that spans the column's width beside the
517
517
  sidebar, under the app bar, the breadcrumb and the content. The layer is `inert`, `aria-hidden="true"`
518
518
  and takes no pointer, so the preset is decoration only: put nothing
519
519
  interactive in it.
520
520
  - **It fills the column.** A `Background` in the layer is sized to the layer,
521
- not to `100lvw × 100lvh`, so you need no `className` or `fill`. In
522
- `scroll="document"` the column grows with the content, and so does the preset.
523
- - **The shapes stay in the free content area.** Under a `backdrop`, every
524
- surface of the chrome is opaque, so no shape runs behind a text, an icon or a
525
- control: the sidebar (over its full height), the app bar, the breadcrumb (a
526
- pill as wide as its crumbs), the tabs strip, the lists and tables (band and
527
- rows), the segmented `ToggleGroup`, the list bar and the phone tiles. Nothing
528
- changes without a `backdrop`. Two tokens set the colours, on the layout (a
529
- `className` such as `[--nxgt-backdrop-chrome:var(--muted)]`) or on any
530
- ancestor:
521
+ not to `100lvw × 100lvh`, so you need no `className` or `fill`. The layer is
522
+ as wide as the column and one viewport high, and stays in the viewport while
523
+ the content scrolls over it, in `scroll="document"` (the page scrolls) and in
524
+ `scroll="container"` alike.
525
+ - **The chrome is lightly translucent and frosted.** Under a `backdrop`, the
526
+ app bar, the breadcrumb (a pill as wide as its crumbs) and the tabs strip
527
+ show a shape faintly through their fill, over a 6px blur that keeps it from
528
+ competing with a text. The lists and tables (band and rows), the segmented
529
+ `ToggleGroup`, the list bar, the phone tiles and the cards stay opaque, so no
530
+ shape runs behind a row. The sidebar is frosted too (87%), but the layer is
531
+ only in the content column, so no shape is drawn behind it. Nothing changes
532
+ without a `backdrop`. Two tokens set the colours, on the layout (a `className`
533
+ such as `[--nxgt-backdrop-chrome:var(--muted)]`) or on any ancestor:
531
534
 
532
535
  | Token | Paints | Default |
533
536
  | --- | --- | --- |
534
- | `--nxgt-backdrop-chrome` | sidebar, app bar, breadcrumb, tabs strip | `var(--background)` |
535
- | `--nxgt-backdrop-surface` | lists and tables (`DataTable`, `ServerTable`) | `var(--card)` |
537
+ | `--nxgt-backdrop-chrome` | sidebar, app bar, breadcrumb, tabs strip | `--background` at 80% (app bar) or 87% (sidebar, breadcrumb, tabs strip), over a 6px blur |
538
+ | `--nxgt-backdrop-surface` | lists and tables (`DataTable`, `ServerTable`) | `var(--card)`, opaque |
536
539
 
537
540
  ```tsx
538
541
  <ActivityLayout
@@ -541,12 +544,19 @@ export function Shell({ items }: { items: MenuItem[] }) {
541
544
  >
542
545
  ```
543
546
 
544
- Give a colour, not a translucent one: a see-through surface lets the shapes
545
- run behind the text again. Tone the preset down with its `intensity`
546
- (`subtle`) rather than restyling the frame. The backdrop shows only inside
547
- the content column (its layer is in the column, rounded like the frame): the
548
- frame's padding, the gap beside the sidebar and the strip above the app bar
549
- are the chrome colour, so no shape is cut at the edges.
547
+ The 87% is the least that keeps the sidebar's, the breadcrumb's and the tabs'
548
+ text at 4.5:1 over the darkest shape of the `shapes` preset in the light
549
+ theme (the app bar's text and every icon and the tab indicator pass at 80%,
550
+ by a wide margin in the dark theme). Under
551
+ `@media (prefers-reduced-transparency: reduce)`, and where `backdrop-filter`
552
+ is unsupported, the blur is off and the fill is 92%. `--nxgt-backdrop-chrome`
553
+ replaces the fill whole, so a colour you give is not translucent unless you
554
+ make it so; a see-through colour lets the shapes run behind the text, so check
555
+ its contrast over the preset you use. Tone the preset down with its
556
+ `intensity` (`subtle`) rather than restyling the frame. The backdrop shows
557
+ only inside the content column (its layer is in the column, rounded like the
558
+ frame): the frame's padding, the gap beside the sidebar and the strip above
559
+ the app bar are the chrome colour, so no shape is cut at the edges.
550
560
  - **The stylesheet is yours to import.** `@nxgt/material/backgrounds` is a
551
561
  separate entry, so `ActivityLayout` never pulls it in: import it where you
552
562
  build the `backdrop`, and its `backgrounds.css` once.
@@ -1324,19 +1324,14 @@ import { Background } from '@nxgt/material/backgrounds';
1324
1324
  import '@nxgt/material/backgrounds.css';
1325
1325
  ```
1326
1326
 
1327
- ### Shapes of an `ActivityLayout` `backdrop` run behind the text of the chrome or a list
1327
+ ### Shapes of an `ActivityLayout` `backdrop` show through the chrome, or run behind the text of a list
1328
1328
 
1329
- **When:** with `backdrop`, a breadcrumb, a tabs strip, a table or the sidebar
1330
- shows the shapes through it, or you set a translucent colour and they come back.
1331
- **Why:** under `data-backdrop` those surfaces take `--nxgt-backdrop-chrome` (default
1332
- `var(--background)`) and `--nxgt-backdrop-surface` (default `var(--card)`); before
1333
- 3.7.2 they had no surface or a translucent one, and a custom `className` with its
1334
- own `bg-*` on a list wins over the token.
1335
- **Fix:** update `@nxgt/material`, and give the tokens opaque colours; drop a
1336
- `bg-*/NN` class from the list's `className`.
1329
+ **When:** with `backdrop`, the app bar, the breadcrumb, the tabs strip or the sidebar shows the shapes faintly through it; or a table or list shows them behind its rows, or a colour of your own made them come back.
1330
+ **Why:** the chrome is deliberately lightly translucent and frosted: under `data-backdrop` it takes `--nxgt-backdrop-chrome` (default `--background` at 80% for the app bar, 87% for the sidebar, breadcrumb and tabs strip, over a 6px blur; 92% and no blur under `prefers-reduced-transparency` or without `backdrop-filter`). The lists take `--nxgt-backdrop-surface` (default `var(--card)`, opaque); a custom `className` with its own `bg-*` on a list wins over the token, and before 3.7.2 lists had no surface or a translucent one.
1331
+ **Fix:** for a solid chrome, set `--nxgt-backdrop-chrome` to an opaque colour. A translucent colour of your own needs a contrast check over the preset you use. For a list, update `@nxgt/material`, set `--nxgt-backdrop-surface` to an opaque colour and drop a `bg-*/NN` class from its `className`.
1337
1332
 
1338
1333
  ```tsx
1339
- <ActivityLayout backdrop={<Background preset="shapes" />} className="[--nxgt-backdrop-surface:var(--background)]" />
1334
+ <ActivityLayout backdrop={<Background preset="shapes" />} className="[--nxgt-backdrop-chrome:var(--background)] [--nxgt-backdrop-surface:var(--background)]" />
1340
1335
  ```
1341
1336
 
1342
1337
  ### A ResponsiveButton no longer shows its tooltip next to its visible label
@@ -9,13 +9,18 @@
9
9
  * frame's padding and gaps take the chrome fill, so the shapes show nowhere
10
10
  * else.
11
11
  *
12
- * The shapes show in the free content area only: every surface of the chrome and
13
- * of the lists is opaque, so none runs behind a text, an icon or a control. Two
14
- * tokens, set on the layout (or any ancestor), tune them:
12
+ * The chrome is lightly translucent and frosted: about 80% of the background
13
+ * colour (--nxgt-backdrop-chrome-alpha, the app bar) or 87% (--nxgt-backdrop-nav-alpha,
14
+ * the sidebar, the breadcrumb and the tabs strip, whose text needs it to keep
15
+ * WCAG AA over the darkest shape in the light theme) over a 6px blur
16
+ * (--nxgt-backdrop-blur), so a shape shows faintly behind them, too blurred to
17
+ * compete with a text. The lists, tables and cards stay opaque. Under `prefers-reduced-transparency:
18
+ * reduce`, or where `backdrop-filter` is unsupported, the blur is off and the
19
+ * fill is 92% (both). Two tokens, set on the layout (or any ancestor), tune them:
15
20
  * --nxgt-backdrop-chrome the sidebar, the app bar, the breadcrumb, the tabs
16
- * strip (default: var(--background))
21
+ * strip (default: the background at 80% / 92%)
17
22
  * --nxgt-backdrop-surface the lists and tables, their band and rows
18
- * (default: var(--card))
23
+ * (default: var(--card), opaque)
19
24
  * The sidebar, the app bar and the tables take theirs from a class whose
20
25
  * fallback is their usual surface, through `--nxgt-backdrop-fill-*`: a utility
21
26
  * class outranks any rule in a layer, so a rule here could not set them. */
@@ -35,11 +40,69 @@
35
40
  height: 100%;
36
41
  }
37
42
 
43
+ /* The layer is sticky, not absolute: it keeps the column's left and right
44
+ * edges and stays in the viewport, from the app bar's top to the frame's
45
+ * bottom padding, while the page (scroll="document") or the content region
46
+ * (scroll="container") scrolls over it. It is the column's first child, so
47
+ * a negative bottom margin (its height, and the column's 0.5rem gap) takes
48
+ * it out of the flow: the app bar keeps its place. The offsets are the
49
+ * frame's own padding and the app bar's sticky top. */
50
+ [data-slot="activity-layout-backdrop"] {
51
+ --nxgt-backdrop-top: max(0.5rem, env(safe-area-inset-top));
52
+ --nxgt-backdrop-height: calc(
53
+ 100dvh -
54
+ var(--nxgt-backdrop-top) -
55
+ max(0.5rem, env(safe-area-inset-bottom)) -
56
+ var(--nxgt-media-dock, 0px)
57
+ );
58
+ position: sticky;
59
+ top: var(--nxgt-backdrop-top);
60
+ height: var(--nxgt-backdrop-height);
61
+ margin-bottom: calc(-1 * var(--nxgt-backdrop-height) - 0.5rem);
62
+ }
63
+
38
64
  [data-slot="activity-layout"][data-backdrop] {
39
- --nxgt-backdrop-fill-chrome: var(--nxgt-backdrop-chrome, var(--background));
65
+ --nxgt-backdrop-chrome-alpha: 80%;
66
+ --nxgt-backdrop-nav-alpha: 87%;
67
+ --nxgt-backdrop-blur: 6px;
68
+ --nxgt-backdrop-fill-chrome: var(
69
+ --nxgt-backdrop-chrome,
70
+ color-mix(
71
+ in oklab,
72
+ var(--background) var(--nxgt-backdrop-chrome-alpha),
73
+ transparent
74
+ )
75
+ );
76
+ --nxgt-backdrop-fill-nav: var(
77
+ --nxgt-backdrop-chrome,
78
+ color-mix(
79
+ in oklab,
80
+ var(--background) var(--nxgt-backdrop-nav-alpha),
81
+ transparent
82
+ )
83
+ );
40
84
  --nxgt-backdrop-fill-surface: var(--nxgt-backdrop-surface, var(--card));
41
85
  }
42
86
 
87
+ /* No blur to lean on: a more opaque fill instead. */
88
+ @supports not (
89
+ (backdrop-filter: blur(1px)) or
90
+ (-webkit-backdrop-filter: blur(1px))
91
+ ) {
92
+ [data-slot="activity-layout"][data-backdrop] {
93
+ --nxgt-backdrop-chrome-alpha: 92%;
94
+ --nxgt-backdrop-nav-alpha: 92%;
95
+ --nxgt-backdrop-blur: 0px;
96
+ }
97
+ }
98
+ @media (prefers-reduced-transparency: reduce) {
99
+ [data-slot="activity-layout"][data-backdrop] {
100
+ --nxgt-backdrop-chrome-alpha: 92%;
101
+ --nxgt-backdrop-nav-alpha: 92%;
102
+ --nxgt-backdrop-blur: 0px;
103
+ }
104
+ }
105
+
43
106
  /* The breadcrumb trail: a pill under the app bar, as wide as its crumbs. */
44
107
  [data-slot="activity-layout"][data-backdrop]
45
108
  [data-slot="activity-layout-frame"]
@@ -50,7 +113,9 @@
50
113
  padding-block: 0.25rem;
51
114
  padding-inline-end: 0.75rem;
52
115
  border-radius: 999px;
53
- background: var(--nxgt-backdrop-fill-chrome);
116
+ background: var(--nxgt-backdrop-fill-nav);
117
+ -webkit-backdrop-filter: blur(var(--nxgt-backdrop-blur));
118
+ backdrop-filter: blur(var(--nxgt-backdrop-blur));
54
119
  }
55
120
 
56
121
  /* Tabs: the strip is a band, its top corners rounded. (The segmented look
@@ -58,6 +123,8 @@
58
123
  [data-slot="activity-layout"][data-backdrop] [data-slot="tabs-list"] {
59
124
  border-start-start-radius: var(--radius);
60
125
  border-start-end-radius: var(--radius);
61
- background: var(--nxgt-backdrop-fill-chrome);
126
+ background: var(--nxgt-backdrop-fill-nav);
127
+ -webkit-backdrop-filter: blur(var(--nxgt-backdrop-blur));
128
+ backdrop-filter: blur(var(--nxgt-backdrop-blur));
62
129
  }
63
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.7.2",
3
+ "version": "3.7.4",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"