@nxgt/material 3.15.0 → 3.16.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 +6 -0
- package/README.md +1 -1
- package/dist/{components-j0Iv8MZi.js → components-BOF9frx3.js} +1165 -1065
- package/dist/components.js +1 -1
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside.d.ts +22 -0
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside.types.d.ts +36 -0
- package/dist/lib/components/ui/layout/app-shell/activity-content.d.ts +15 -2
- package/dist/lib/components/ui/layout/app-shell/index.d.ts +1 -0
- package/dist/main.js +1 -1
- package/dist/material.css +1 -1
- package/docs/components/navigation-and-layout.md +3 -0
- package/docs/guides/app-shell.md +52 -0
- package/docs/guides/theming.md +1 -0
- package/docs/troubleshooting.md +24 -0
- package/package.json +1 -1
|
@@ -81,6 +81,9 @@ phone's menu sheet pad clear of `env(safe-area-inset-*)`, as classes; see the
|
|
|
81
81
|
| `menuOpen` / `onMenuOpenChange` | `boolean` / `(open: boolean) => void` | — | control the phone's menu sheet; it still closes by itself when a link in it is followed or the location changes (see the [app shell guide](../guides/app-shell.md#activitylayout)) |
|
|
82
82
|
| `titleAs` | `'h1'` … `'h6'` \| `'div'` | `'h1'` | `ActivityContent`: the title's heading level |
|
|
83
83
|
| `inset` | `boolean` | `false` | `ActivityContent`: pads the content 1rem on each side. Off, it lines up with the app bar and the cards |
|
|
84
|
+
| `width` | `'full' \| 'form' \| 'reading'` | `'full'` | `ActivityContent`: caps the main column at 48rem (`'form'`) or 72ch (`'reading'`), the side panel right beside it |
|
|
85
|
+
| `aside`, `asideLabel` / `asideLabelledBy` | `ReactNode`, `string` | — | `ActivityContent`: a side panel, a named `complementary` landmark, beside the content from 1280px (CSS only), stacked below; sticky under the app bar |
|
|
86
|
+
| `asideSide` / `asideWidth` / `asideFrom` / `asideSticky` / `asideStack` | `'start' \| 'end'` / `'sm' \| 'md' \| 'lg' \| string` / `'lg' \| 'xl' \| '2xl'` / `boolean` / `'before' \| 'after'` | `'end'` / `'md'` / `'xl'` / `true` / `'after'` | `ActivityContent`: the panel's side, width (16, 20, 24rem), breakpoint, stickiness and stacking order (see the [app shell guide](../guides/app-shell.md#a-side-panel-and-a-readable-width)) |
|
|
84
87
|
| `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 |
|
|
85
88
|
| `backdrop` | `ReactNode \| false` | — | `ActivityLayout`: an exception to the theme's background (drawn by default; Lavande's is the built-in gradient and blobs); `false` draws a plain page. A node is a decorative background behind the frame: 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) |
|
|
86
89
|
| `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) |
|
package/docs/guides/app-shell.md
CHANGED
|
@@ -799,6 +799,15 @@ export function BoardShell({ items }: { items: MenuItem[] }) {
|
|
|
799
799
|
| `hideHeader` | `boolean` | `false` | No header card |
|
|
800
800
|
| `titleAs` | `'h1'` … `'h6'` \| `'div'` | `'h1'` | The title's element: the screen's heading, `'h2'` under a heading of yours, `'div'` for none |
|
|
801
801
|
| `inset` | `boolean` | `false` | Pads the content 1rem on each side. Off, it lines up with the app bar and the cards |
|
|
802
|
+
| `width` | `'full'` \| `'form'` \| `'reading'` | `'full'` | Caps the main column: `'form'` 48rem, `'reading'` 72ch. The header card keeps the full width |
|
|
803
|
+
| `aside` | `ReactNode` | — | A side panel: beside the content from `asideFrom`, stacked below it |
|
|
804
|
+
| `asideLabel` / `asideLabelledBy` | `string` | — | The panel's accessible name (`aria-label`), or the id of a heading inside it (`aria-labelledby`). One of them is needed |
|
|
805
|
+
| `asideSide` | `'start'` \| `'end'` | `'end'` | Which side of the content the panel sits on, wide |
|
|
806
|
+
| `asideWidth` | `'sm'` \| `'md'` \| `'lg'` \| a CSS length | `'md'` | 16, 20 or 24rem; `'md'` reads the `--nxgt-aside-width` token (20rem) |
|
|
807
|
+
| `asideFrom` | `'lg'` \| `'xl'` \| `'2xl'` | `'xl'` | The viewport width (1024, 1280 or 1536px) from which the panel is beside the content |
|
|
808
|
+
| `asideSticky` | `boolean` | `true` | Keeps the panel under the app bar while the page scrolls; it scrolls inside itself when taller than the window |
|
|
809
|
+
| `asideStack` | `'before'` \| `'after'` | `'after'` | Where the panel goes below `asideFrom`, in the DOM and on screen |
|
|
810
|
+
| `asideClassName` | `string` | — | Classes for the panel |
|
|
802
811
|
|
|
803
812
|
```tsx
|
|
804
813
|
import { ActivityContent, Button } from '@nxgt/material/components';
|
|
@@ -819,6 +828,49 @@ export function InvoicesPage() {
|
|
|
819
828
|
The header card wraps: on a narrow screen the actions go under the title
|
|
820
829
|
instead of squeezing it, and a long title wraps rather than scrolling.
|
|
821
830
|
|
|
831
|
+
### A side panel and a readable width
|
|
832
|
+
|
|
833
|
+
A record's alerts and key facts, a dashboard's counts, a form's help: pass them
|
|
834
|
+
as `aside`. From `asideFrom` (`'xl'`, a 1280px window) the panel sits beside the
|
|
835
|
+
main column and sticks under the app bar; below it, the panel stacks after the
|
|
836
|
+
content (`asideStack="before"` puts it first). The switch is CSS only: the
|
|
837
|
+
server's HTML and a phone's first paint are already right, and no JavaScript
|
|
838
|
+
decides the layout.
|
|
839
|
+
|
|
840
|
+
```tsx
|
|
841
|
+
<ActivityContent
|
|
842
|
+
title="New visit"
|
|
843
|
+
width="form"
|
|
844
|
+
aside={<DuplicateHints />}
|
|
845
|
+
asideLabel="Possible duplicates"
|
|
846
|
+
>
|
|
847
|
+
<VisitForm />
|
|
848
|
+
</ActivityContent>
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
- **Landmark.** The panel is an `<aside>`, a `complementary` landmark: name it
|
|
852
|
+
with `asideLabel`, or with `asideLabelledBy` (the id of its heading). Its
|
|
853
|
+
content is the panel's own; give it one `h2` when it has a heading.
|
|
854
|
+
- **Sticky, in every scroll mode.** With `scroll="document"` the panel sticks
|
|
855
|
+
under the app bar (the bar's gutter, its `--nxgt-header-height` and 0.5rem);
|
|
856
|
+
with `scroll="container"` it sticks to the top of the content region. It is as
|
|
857
|
+
tall as the window at most and scrolls inside itself, and becomes focusable
|
|
858
|
+
(`tabindex="0"`) only while it does, so a keyboard reaches what overflows. A
|
|
859
|
+
`scroll="document"` page needs no `overflow` on any ancestor of the screen
|
|
860
|
+
(see [the troubleshooting entry](../troubleshooting.md#the-side-panel-does-not-stick)).
|
|
861
|
+
- **A capped column sits beside its panel.** `width="form"` or `"reading"` caps
|
|
862
|
+
the main column and the pair stays start-aligned: at 1920px the panel is 1rem
|
|
863
|
+
from the fields, not at the window's far edge. The header card above keeps
|
|
864
|
+
the full width. `width` also works without a panel.
|
|
865
|
+
- **The breakpoint is the window's.** `asideFrom` follows the viewport, not the
|
|
866
|
+
content column, which the sidebar and the gutters narrow a little: pick `'lg'`
|
|
867
|
+
for a panel on a smaller window, `'2xl'` to keep it stacked on all but the
|
|
868
|
+
widest.
|
|
869
|
+
- **A size container.** With a panel, the main column is an `@container`, so a
|
|
870
|
+
`ResponsiveGrid` inside it follows the column's width.
|
|
871
|
+
- **Width token.** `--nxgt-aside-width` changes `asideWidth="md"` (20rem) app-wide;
|
|
872
|
+
any CSS length goes in `asideWidth` for one screen.
|
|
873
|
+
|
|
822
874
|
## Breadcrumbs
|
|
823
875
|
|
|
824
876
|
`AppBreadcrumb` (rendered by `ActivityLayout`) starts with a home icon linking
|
package/docs/guides/theming.md
CHANGED
|
@@ -625,6 +625,7 @@ centre line from `md` (48rem) up:
|
|
|
625
625
|
| Token | Default | Reads |
|
|
626
626
|
| --- | --- | --- |
|
|
627
627
|
| `--nxgt-header-height` | `4rem` | the app bar (all widths) and the rail's header (`md` and up) |
|
|
628
|
+
| `--nxgt-aside-width` | `20rem` | an `ActivityContent` side panel with `asideWidth="md"` (the default) |
|
|
628
629
|
|
|
629
630
|
```css
|
|
630
631
|
:root {
|
package/docs/troubleshooting.md
CHANGED
|
@@ -1338,6 +1338,30 @@ top (`align="start"`).
|
|
|
1338
1338
|
<ActivityLayout items={items} align="center">…</ActivityLayout>
|
|
1339
1339
|
```
|
|
1340
1340
|
|
|
1341
|
+
### The side panel does not stick
|
|
1342
|
+
|
|
1343
|
+
**When:** an `ActivityContent` `aside` scrolls away with the page instead of
|
|
1344
|
+
staying under the app bar, or it is not beside the content at 1280px.
|
|
1345
|
+
**Why:** `position: sticky` sticks inside its nearest scrolling ancestor, and
|
|
1346
|
+
any ancestor with an `overflow` other than `visible` (`overflow-hidden`,
|
|
1347
|
+
`overflow-auto`, `overflow-clip`; a `PaneLayout`'s root has `overflow-hidden`)
|
|
1348
|
+
becomes that scroller, which does not scroll, so the panel never moves. A
|
|
1349
|
+
wrapper of yours around the screen, or an `ActivityLayout` with
|
|
1350
|
+
`scroll="container"` where you meant `"document"`, does the same. Below
|
|
1351
|
+
`asideFrom` (1280px by default) the panel is stacked and not sticky on
|
|
1352
|
+
purpose, and the breakpoint is the window's width, not the column's.
|
|
1353
|
+
**Fix:** take the `overflow` off every ancestor between `ActivityLayout` and
|
|
1354
|
+
`ActivityContent`, or move it onto an element inside the screen; use
|
|
1355
|
+
`scroll="document"` (the default). Find the culprit in the console:
|
|
1356
|
+
|
|
1357
|
+
```js
|
|
1358
|
+
for (let el = document.querySelector('[data-slot="activity-content-aside"]').parentElement; el; el = el.parentElement)
|
|
1359
|
+
if (getComputedStyle(el).overflowY !== 'visible') console.log(el);
|
|
1360
|
+
```
|
|
1361
|
+
|
|
1362
|
+
With `scroll="container"` the region itself is the scroller, and the panel
|
|
1363
|
+
sticks to its top: that is expected.
|
|
1364
|
+
|
|
1341
1365
|
### axe reports `target-size` on a control under a form's sticky actions
|
|
1342
1366
|
|
|
1343
1367
|
**When:** since the form's actions stick to the bottom (see above), axe's
|