@gjsify/adwaita-web 0.33.0 → 0.35.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/adwaita-web.css +46 -5
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +6 -6
- package/scss/_navigation_split_view.scss +5 -1
- package/scss/_navigation_view.scss +28 -4
- package/scss/_overlay_split_view.scss +5 -1
- package/scss/_panes.scss +57 -0
- package/scss/_sidebar.scss +8 -1
- package/scss/_theme.scss +9 -0
- package/scss/_variables.scss +18 -1
- package/scss/adwaita-skin.scss +1 -0
- package/src/adw-about-dialog.spec.ts +36 -0
- package/src/adw-sidebar.spec.ts +32 -0
- package/src/elements/adw-navigation-split-view.ts +10 -0
- package/src/elements/adw-overlay-split-view.ts +17 -0
- package/src/split-views.spec.ts +91 -0
- package/src/styles.generated.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/adwaita-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Adwaita/Libadwaita web components for browser targets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"@codemirror/language": "^6.12.4",
|
|
42
42
|
"@codemirror/state": "^6.7.0",
|
|
43
43
|
"@codemirror/view": "^6.43.4",
|
|
44
|
-
"@gjsify/adwaita-core": "^0.
|
|
45
|
-
"@gjsify/adwaita-fonts": "^0.
|
|
46
|
-
"@gjsify/adwaita-icons": "^0.
|
|
44
|
+
"@gjsify/adwaita-core": "^0.35.0",
|
|
45
|
+
"@gjsify/adwaita-fonts": "^0.35.0",
|
|
46
|
+
"@gjsify/adwaita-icons": "^0.35.0",
|
|
47
47
|
"@lezer/highlight": "^1.2.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@gjsify/cli": "^0.
|
|
51
|
-
"@gjsify/unit": "^0.
|
|
50
|
+
"@gjsify/cli": "^0.35.0",
|
|
51
|
+
"@gjsify/unit": "^0.35.0",
|
|
52
52
|
"sass": "^1.101.0",
|
|
53
53
|
"typescript": "^6.0.3"
|
|
54
54
|
},
|
|
@@ -22,12 +22,16 @@ adw-navigation-split-view {
|
|
|
22
22
|
min-width: 0;
|
|
23
23
|
flex: 1 1 auto;
|
|
24
24
|
|
|
25
|
+
// NO background here — it comes from the `.sidebar-pane` class the element
|
|
26
|
+
// applies while DOCKED (see _panes.scss). Collapsed, libadwaita builds no
|
|
27
|
+
// pane bins at all and the sidebar is an ordinary full-window navigation
|
|
28
|
+
// page; a background nailed to this private class made it sidebar-coloured
|
|
29
|
+
// at every width.
|
|
25
30
|
.adw-nsv-sidebar {
|
|
26
31
|
display: flex;
|
|
27
32
|
flex-direction: column;
|
|
28
33
|
min-height: 0;
|
|
29
34
|
flex-shrink: 0;
|
|
30
|
-
background-color: var(--sidebar-bg-color);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
// The container MINIMUM, as CSS spells it: `measure_uncollapsed`
|
|
@@ -16,9 +16,13 @@ adw-navigation-view {
|
|
|
16
16
|
background-color: var(--window-bg-color);
|
|
17
17
|
color: var(--window-fg-color);
|
|
18
18
|
|
|
19
|
-
// The page stack — fills the view
|
|
19
|
+
// The page stack — fills the view when it is given a height, and MEASURES the
|
|
20
|
+
// visible page when it is not. A flex column rather than a positioning
|
|
21
|
+
// context: the page is an in-flow item, so its content reaches the view.
|
|
20
22
|
.adw-navigation-view-pages {
|
|
21
23
|
flex: 1 1 auto;
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
22
26
|
position: relative;
|
|
23
27
|
box-sizing: border-box;
|
|
24
28
|
min-height: 0;
|
|
@@ -26,11 +30,31 @@ adw-navigation-view {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
// A single navigation page — the visible one fills the view, the rest are
|
|
29
|
-
//
|
|
33
|
+
// `display: none`.
|
|
34
|
+
//
|
|
35
|
+
// IN FLOW, not absolute. It was `position: absolute; inset: 0` under a comment
|
|
36
|
+
// saying it had to be "so a transition can overlap two pages" — but two pages
|
|
37
|
+
// never overlap here: `adw-navigation-view.ts` marks every page but the
|
|
38
|
+
// visible one `[hidden]`, which is `display: none` below, and the push
|
|
39
|
+
// animation runs on `.visible-page` alone. So the absolute positioning bought
|
|
40
|
+
// an overlap that does not happen, and what it cost was the HEIGHT: an
|
|
41
|
+
// absolutely-positioned child contributes nothing to its parent, so the page
|
|
42
|
+
// stack measured 0, the view above it measured 0, and the page — `inset: 0` of
|
|
43
|
+
// a zero-height parent — measured 0 in turn. A closed circle.
|
|
44
|
+
//
|
|
45
|
+
// Inside a window that never showed, because a definite height arrived from
|
|
46
|
+
// outside. `<adw-about-dialog>` is the case where none does: its sheet is
|
|
47
|
+
// `position: fixed` with a width and no height, exactly as
|
|
48
|
+
// `adw-about-dialog.ui` declares it (`content-width` 360, no content-height —
|
|
49
|
+
// libadwaita takes the height from the content). The whole dialog rendered
|
|
50
|
+
// invisible, with a header bar inside it genuinely measuring 47px.
|
|
51
|
+
//
|
|
52
|
+
// `flex: 1 1 auto` keeps the fill: given a height the page still grows into
|
|
53
|
+
// it; without one it reports its content.
|
|
30
54
|
.adw-navigation-page {
|
|
31
55
|
box-sizing: border-box;
|
|
32
|
-
position:
|
|
33
|
-
|
|
56
|
+
position: relative;
|
|
57
|
+
flex: 1 1 auto;
|
|
34
58
|
display: flex;
|
|
35
59
|
flex-direction: column;
|
|
36
60
|
overflow: auto;
|
|
@@ -27,8 +27,12 @@ adw-overlay-split-view {
|
|
|
27
27
|
position: relative;
|
|
28
28
|
overflow: hidden;
|
|
29
29
|
|
|
30
|
+
// NO background here. The pane colour comes from the `.sidebar-pane` /
|
|
31
|
+
// `.overlay-pane` class the element toggles (see _panes.scss), because which
|
|
32
|
+
// of the two a pane is in is exactly what decides its colour — hard-coding
|
|
33
|
+
// `--sidebar-bg-color` on this private class painted a collapsed overlay,
|
|
34
|
+
// which libadwaita puts on the window background, as though it were docked.
|
|
30
35
|
.adw-osv-sidebar {
|
|
31
|
-
background-color: var(--sidebar-bg-color);
|
|
32
36
|
overflow-y: auto;
|
|
33
37
|
flex-shrink: 0;
|
|
34
38
|
z-index: 10;
|
package/scss/_panes.scss
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// _panes.scss — `.sidebar-pane` / `.content-pane` / `.overlay-pane`.
|
|
2
|
+
//
|
|
3
|
+
// These are libadwaita STYLE CLASSES, not private markup of one widget. Both
|
|
4
|
+
// split views document them as their CSS node tree
|
|
5
|
+
// (adw-navigation-split-view.c:157-165, adw-overlay-split-view.c:136-152) and
|
|
6
|
+
// both apply them to their pane bins, which makes them the supported hook an
|
|
7
|
+
// app themes a pane through. They lived nowhere in this stylesheet, so each
|
|
8
|
+
// split view hard-coded `--sidebar-bg-color` onto its own private pane div
|
|
9
|
+
// instead — with two consequences.
|
|
10
|
+
//
|
|
11
|
+
// The first is that an app writing the documented selector styles nothing, and
|
|
12
|
+
// gets no error saying so. Our own docs site is the evidence: every split-view
|
|
13
|
+
// example carried `class="sidebar"` on the sidebar toolbar view, hand-written
|
|
14
|
+
// by someone reaching for exactly this, matching no rule in the build.
|
|
15
|
+
//
|
|
16
|
+
// The second is a rendering defect, because the class is not constant — it is
|
|
17
|
+
// how the widget says which of its states a pane is in. A collapsed overlay
|
|
18
|
+
// sidebar is an `.overlay-pane`, on the WINDOW background, not the sidebar one
|
|
19
|
+
// (adw-overlay-split-view.c:718-741); a collapsed navigation split view has no
|
|
20
|
+
// pane bins at all, its pages being ordinary navigation pages. Painting the
|
|
21
|
+
// sidebar colour at every width, as the private rules did, got both wrong.
|
|
22
|
+
//
|
|
23
|
+
// Reference: refs/libadwaita/src/stylesheet/widgets/_sidebars.scss (.sidebar-pane, .overlay-pane)
|
|
24
|
+
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
25
|
+
// Modifications: Adapted for @gjsify/adwaita-web Web Components.
|
|
26
|
+
|
|
27
|
+
.sidebar-pane {
|
|
28
|
+
background-color: var(--sidebar-bg-color);
|
|
29
|
+
color: var(--sidebar-fg-color);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// A pane nested inside another sidebar pane defers to it rather than stacking a
|
|
33
|
+
// second tint (`.sidebar-pane .sidebar-pane`, _sidebars.scss). libadwaita also
|
|
34
|
+
// recolours the MIDDLE pane of a three-pane setup through
|
|
35
|
+
// `--secondary-sidebar-*`; that needs a split view nested in a split view to
|
|
36
|
+
// mean anything, and no such composition is rendered yet, so the tokens are
|
|
37
|
+
// defined (they are public API an app may already reference) and the selector
|
|
38
|
+
// is left for whoever builds the composition that can test it.
|
|
39
|
+
.sidebar-pane .sidebar-pane {
|
|
40
|
+
background-color: transparent;
|
|
41
|
+
color: inherit;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// `.content-pane` deliberately has NO rule here. libadwaita gives it no colour
|
|
45
|
+
// of its own — the window shows through — and writing `transparent` would be a
|
|
46
|
+
// claim, not a copy: it would override the `--window-bg-color` the navigation
|
|
47
|
+
// split view sets on its own content pane for the case where the view is not a
|
|
48
|
+
// window's direct child. The class is still applied, because being able to
|
|
49
|
+
// select it is the point.
|
|
50
|
+
|
|
51
|
+
// Collapsed: the sidebar floats ABOVE the content as a temporary panel, and
|
|
52
|
+
// libadwaita gives it the window colours rather than the sidebar ones — a panel
|
|
53
|
+
// over the content is not the same surface as a pane beside it.
|
|
54
|
+
.overlay-pane {
|
|
55
|
+
background-color: var(--window-bg-color);
|
|
56
|
+
color: var(--window-fg-color);
|
|
57
|
+
}
|
package/scss/_sidebar.scss
CHANGED
|
@@ -62,12 +62,19 @@ adw-sidebar {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// --- A single item row ---
|
|
65
|
+
//
|
|
66
|
+
// NO `width: 100%`. The list is a column flex container, so a row already
|
|
67
|
+
// stretches to it — and stretching SUBTRACTS the row's own margins, which is
|
|
68
|
+
// what puts the same 6px of air on both sides. `width: 100%` resolves against
|
|
69
|
+
// the containing block INSTEAD, which does not know about the margins, so
|
|
70
|
+
// every row came out 12px too wide: inset 6px on the left, hanging 6px past
|
|
71
|
+
// the right edge with its rounded corners cut off by the pane. Visible on any
|
|
72
|
+
// selected or hovered row, because only a filled row shows where it ends.
|
|
65
73
|
.adw-sidebar-item {
|
|
66
74
|
box-sizing: border-box;
|
|
67
75
|
display: flex;
|
|
68
76
|
align-items: center;
|
|
69
77
|
gap: var(--spacing-m);
|
|
70
|
-
width: 100%;
|
|
71
78
|
min-height: 36px;
|
|
72
79
|
// The native row has a context menu, so padding lives on the inner box and
|
|
73
80
|
// the row itself carries the menu margin + radius.
|
package/scss/_theme.scss
CHANGED
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|
--headerbar-shade-color: rgba(0, 0, 6, 0.36);
|
|
15
15
|
--separator-color: rgba(255, 255, 255, 0.08);
|
|
16
16
|
--sidebar-bg-color: #2e2e32;
|
|
17
|
+
--sidebar-fg-color: #ffffff;
|
|
18
|
+
--sidebar-backdrop-color: #28282c;
|
|
19
|
+
--sidebar-shade-color: rgba(0, 0, 6, 0.25);
|
|
20
|
+
--sidebar-border-color: rgba(0, 0, 6, 0.36);
|
|
21
|
+
--secondary-sidebar-bg-color: #28282c;
|
|
22
|
+
--secondary-sidebar-fg-color: #ffffff;
|
|
23
|
+
--secondary-sidebar-backdrop-color: #252529;
|
|
24
|
+
--secondary-sidebar-shade-color: rgba(0, 0, 6, 0.25);
|
|
25
|
+
--secondary-sidebar-border-color: rgba(0, 0, 6, 0.36);
|
|
17
26
|
--card-bg-color: rgba(255, 255, 255, 0.08);
|
|
18
27
|
--card-fg-color: #ffffff;
|
|
19
28
|
--card-shade-color: rgba(0, 0, 6, 0.36);
|
package/scss/_variables.scss
CHANGED
|
@@ -24,8 +24,25 @@
|
|
|
24
24
|
// draws separators, instead of a harsh near-black line on a dark surface.
|
|
25
25
|
--separator-color: rgba(0, 0, 6, 0.1);
|
|
26
26
|
|
|
27
|
-
// Sidebar
|
|
27
|
+
// Sidebar / split panes. libadwaita defines the whole family, not just the
|
|
28
|
+
// background (_colors.scss:47-58), and only the background was here — so
|
|
29
|
+
// `.sidebar-pane` had no foreground to name, and an app overriding
|
|
30
|
+
// `--sidebar-fg-color` was overriding nothing.
|
|
28
31
|
--sidebar-bg-color: #ebebed;
|
|
32
|
+
--sidebar-fg-color: rgba(0, 0, 6, 0.8);
|
|
33
|
+
--sidebar-backdrop-color: #f2f2f4;
|
|
34
|
+
--sidebar-shade-color: rgba(0, 0, 6, 0.07);
|
|
35
|
+
--sidebar-border-color: rgba(0, 0, 6, 0.07);
|
|
36
|
+
|
|
37
|
+
// The MIDDLE pane of a three-pane setup. Nothing renders one yet; the tokens
|
|
38
|
+
// are defined because they are public API an app may already reference, and a
|
|
39
|
+
// half-present family reads as "this one is unsupported" rather than "this
|
|
40
|
+
// composition is not built yet".
|
|
41
|
+
--secondary-sidebar-bg-color: #f3f3f5;
|
|
42
|
+
--secondary-sidebar-fg-color: rgba(0, 0, 6, 0.8);
|
|
43
|
+
--secondary-sidebar-backdrop-color: #f6f6fa;
|
|
44
|
+
--secondary-sidebar-shade-color: rgba(0, 0, 6, 0.07);
|
|
45
|
+
--secondary-sidebar-border-color: rgba(0, 0, 6, 0.07);
|
|
29
46
|
|
|
30
47
|
// Cards / boxed lists
|
|
31
48
|
--card-bg-color: #ffffff;
|
package/scss/adwaita-skin.scss
CHANGED
|
@@ -347,4 +347,40 @@ export const AdwAboutDialogTest = async () => {
|
|
|
347
347
|
mounted.dispose();
|
|
348
348
|
});
|
|
349
349
|
});
|
|
350
|
+
|
|
351
|
+
// AN OPENED DIALOG HAS TO OCCUPY SPACE.
|
|
352
|
+
//
|
|
353
|
+
// Every other test in this file reads the built DOM, and all of them passed
|
|
354
|
+
// while the dialog rendered INVISIBLE — its sheet measured 360×0. The suite
|
|
355
|
+
// could not see that, because none of it looks at geometry.
|
|
356
|
+
//
|
|
357
|
+
// The sheet is `position: fixed` with a width and no height, which is what
|
|
358
|
+
// `adw-about-dialog.ui:7` declares: `content-width` 360 and no
|
|
359
|
+
// content-height, libadwaita taking the height from the content. The content
|
|
360
|
+
// could not supply one — the navigation pages were absolutely positioned, so
|
|
361
|
+
// they contributed nothing to the page stack, which contributed nothing to
|
|
362
|
+
// the view, which left the sheet at zero; and the pages, being `inset: 0` of
|
|
363
|
+
// a zero-height parent, were zero in turn.
|
|
364
|
+
await describe('adw-about-dialog — an opened dialog is actually on screen', async () => {
|
|
365
|
+
await it('gives its sheet a height derived from its content', () => {
|
|
366
|
+
const mounted = mount({ 'application-name': 'Adwaita Storybook', version: '0.11.0' });
|
|
367
|
+
mounted.dialog.setAttribute('open', '');
|
|
368
|
+
|
|
369
|
+
const sheet = mounted.dialog.querySelector('.adw-about-dialog-sheet') as HTMLElement;
|
|
370
|
+
const rect = sheet.getBoundingClientRect();
|
|
371
|
+
// HEIGHT only. The width was never the defect, and pinning it here
|
|
372
|
+
// needs `calc(100vw - 48px)` restated in JS — where `100vw` and
|
|
373
|
+
// `innerWidth` disagree by the scrollbar (360 against a measured
|
|
374
|
+
// 342), so the assertion would report the harness rather than the
|
|
375
|
+
// widget. A test should assert the rule the bug broke.
|
|
376
|
+
expect(rect.height > 0).toBe(true);
|
|
377
|
+
// And not merely the header: the sheet has to be taller than the one
|
|
378
|
+
// child that had a size of its own all along, which is what made the
|
|
379
|
+
// collapse invisible to every other test in this file.
|
|
380
|
+
const header = sheet.querySelector('adw-header-bar') as HTMLElement;
|
|
381
|
+
expect(rect.height > header.getBoundingClientRect().height).toBe(true);
|
|
382
|
+
|
|
383
|
+
mounted.dispose();
|
|
384
|
+
});
|
|
385
|
+
});
|
|
350
386
|
};
|
package/src/adw-sidebar.spec.ts
CHANGED
|
@@ -329,4 +329,36 @@ export const AdwSidebarTest = async () => {
|
|
|
329
329
|
host.remove();
|
|
330
330
|
});
|
|
331
331
|
});
|
|
332
|
+
|
|
333
|
+
// A row's own box, which nothing had ever measured.
|
|
334
|
+
//
|
|
335
|
+
// `.adw-sidebar-item` carried `width: 100%` ON TOP of `margin: 0 6px 2px`.
|
|
336
|
+
// The list is a column flex container, so a row already stretches to it and
|
|
337
|
+
// stretching subtracts margins; `width: 100%` resolves against the
|
|
338
|
+
// containing block instead, which does not, so every row came out 12px too
|
|
339
|
+
// wide — inset on the left, hanging past the right edge with its rounded
|
|
340
|
+
// corners clipped away. Every earlier test asked what a row CONTAINED, so
|
|
341
|
+
// all of them passed.
|
|
342
|
+
await describe('a sidebar row sits inside its list, not over its edge', async () => {
|
|
343
|
+
await it('leaves the same margin on both sides', async () => {
|
|
344
|
+
const { sidebar, host } = mountSidebar([{ items: [{ title: 'Inbox' }, { title: 'Starred' }] }], {
|
|
345
|
+
selected: '0',
|
|
346
|
+
});
|
|
347
|
+
host.setAttribute('style', 'width:220px');
|
|
348
|
+
|
|
349
|
+
const list = sidebar.querySelector('.adw-sidebar-list') as HTMLElement;
|
|
350
|
+
const listBox = list.getBoundingClientRect();
|
|
351
|
+
|
|
352
|
+
for (const row of rowsOf(sidebar)) {
|
|
353
|
+
const box = row.getBoundingClientRect();
|
|
354
|
+
const left = box.left - listBox.left;
|
|
355
|
+
const right = listBox.right - box.right;
|
|
356
|
+
// Symmetric, and INSIDE — a negative right gap is the overhang.
|
|
357
|
+
expect(Math.round(left)).toBe(Math.round(right));
|
|
358
|
+
expect(right >= 0).toBe(true);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
host.remove();
|
|
362
|
+
});
|
|
363
|
+
});
|
|
332
364
|
};
|
|
@@ -273,6 +273,16 @@ export class AdwNavigationSplitView extends HTMLElement {
|
|
|
273
273
|
isSidebarAtVisualStart(state.sidebarPosition, this._direction),
|
|
274
274
|
);
|
|
275
275
|
|
|
276
|
+
// THE PANE STYLE CLASSES, and only while docked. libadwaita builds the
|
|
277
|
+
// two `.sidebar-pane` / `.content-pane` bins in the UNCOLLAPSED branch
|
|
278
|
+
// alone (:583-608); collapsed, both pages move into one AdwNavigationView
|
|
279
|
+
// and neither bin exists (:552-568) — so a collapsed sidebar is a full
|
|
280
|
+
// window page on the WINDOW background, not a sidebar-coloured one.
|
|
281
|
+
// Painting it `--sidebar-bg-color` at every width, as this did, is the
|
|
282
|
+
// same defect the overlay view has with `.overlay-pane`.
|
|
283
|
+
this._sidebarEl?.classList.toggle('sidebar-pane', !state.collapsed);
|
|
284
|
+
this._contentEl?.classList.toggle('content-pane', !state.collapsed);
|
|
285
|
+
|
|
276
286
|
// The STACK, not the two flags: `update_navigation_stack` (:342-405)
|
|
277
287
|
// keeps a LONE child visible whatever `show-content` says, and with
|
|
278
288
|
// `sidebar-position: end` the CONTENT is the root page — so the sidebar
|
|
@@ -442,6 +442,23 @@ export class AdwOverlaySplitView extends HTMLElement {
|
|
|
442
442
|
// alone cannot get right: the divider follows where the pane is DRAWN.
|
|
443
443
|
this.classList.toggle('sidebar-at-visual-start', atStart);
|
|
444
444
|
|
|
445
|
+
// THE PANE STYLE CLASSES, which libadwaita documents as part of this
|
|
446
|
+
// widget's CSS node tree (adw-overlay-split-view.c:138-152) and switches
|
|
447
|
+
// in `update_collapsed` (:718-741): docked, the panes are `.sidebar-pane`
|
|
448
|
+
// and `.content-pane`; collapsed, the sidebar becomes an `.overlay-pane`
|
|
449
|
+
// floating above a content pane that carries no class at all.
|
|
450
|
+
//
|
|
451
|
+
// They are not decoration. `.overlay-pane` is what makes a collapsed
|
|
452
|
+
// sidebar drop the sidebar background for the window one, and they are
|
|
453
|
+
// the documented hook an app themes its own panes through — so leaving
|
|
454
|
+
// them off does not merely look wrong, it makes correct app CSS a no-op.
|
|
455
|
+
// The docs site is the proof: its split-view examples carried a
|
|
456
|
+
// hand-written `class="sidebar"` that styled nothing, written by someone
|
|
457
|
+
// reaching for exactly this and finding nothing there.
|
|
458
|
+
this._sidebarEl?.classList.toggle('sidebar-pane', !state.collapsed);
|
|
459
|
+
this._sidebarEl?.classList.toggle('overlay-pane', state.collapsed);
|
|
460
|
+
this._contentEl?.classList.toggle('content-pane', !state.collapsed);
|
|
461
|
+
|
|
445
462
|
// Derived, not re-decided here: the shield only exists while collapsed
|
|
446
463
|
// AND revealed, and each pane is reachable by keyboard only when it is
|
|
447
464
|
// the one on screen.
|
package/src/split-views.spec.ts
CHANGED
|
@@ -890,4 +890,95 @@ export const AdwSplitViewsTest = async () => {
|
|
|
890
890
|
host.remove();
|
|
891
891
|
});
|
|
892
892
|
});
|
|
893
|
+
|
|
894
|
+
// The pane STYLE CLASSES, which libadwaita documents as each split view's
|
|
895
|
+
// CSS node tree and which an app is meant to be able to select.
|
|
896
|
+
//
|
|
897
|
+
// They were absent entirely, and both views hard-coded `--sidebar-bg-color`
|
|
898
|
+
// onto their own private pane class instead. That is not the same thing
|
|
899
|
+
// twice: the class is not constant. It says which STATE a pane is in, and
|
|
900
|
+
// the colour follows from that — so a collapsed overlay sidebar, which
|
|
901
|
+
// libadwaita puts on the window background, was painted as though it were
|
|
902
|
+
// still docked beside the content.
|
|
903
|
+
//
|
|
904
|
+
// Asserting the class names and not only the colours is deliberate. The
|
|
905
|
+
// names are the app-facing contract; a rendering that happened to look right
|
|
906
|
+
// through some other selector would still have broken every app stylesheet
|
|
907
|
+
// written against the documented one.
|
|
908
|
+
await describe('split-view panes carry libadwaita pane style classes', async () => {
|
|
909
|
+
const bg = (el: Element) => getComputedStyle(el).backgroundColor;
|
|
910
|
+
const token = (name: string) => {
|
|
911
|
+
const probe = document.createElement('div');
|
|
912
|
+
probe.style.backgroundColor = `var(${name})`;
|
|
913
|
+
document.body.appendChild(probe);
|
|
914
|
+
const value = getComputedStyle(probe).backgroundColor;
|
|
915
|
+
probe.remove();
|
|
916
|
+
return value;
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
await it('overlay: docked panes are .sidebar-pane / .content-pane', async () => {
|
|
920
|
+
const { view, host } = mount('show-sidebar');
|
|
921
|
+
host.setAttribute('style', 'width:900px;height:300px;display:flex');
|
|
922
|
+
await settle();
|
|
923
|
+
const sidebar = view.querySelector('.adw-osv-sidebar') as HTMLElement;
|
|
924
|
+
const content = view.querySelector('.adw-osv-content') as HTMLElement;
|
|
925
|
+
|
|
926
|
+
expect(sidebar.classList.contains('sidebar-pane')).toBe(true);
|
|
927
|
+
expect(sidebar.classList.contains('overlay-pane')).toBe(false);
|
|
928
|
+
expect(content.classList.contains('content-pane')).toBe(true);
|
|
929
|
+
expect(bg(sidebar)).toBe(token('--sidebar-bg-color'));
|
|
930
|
+
host.remove();
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
await it('overlay: collapsing turns the sidebar into an .overlay-pane on the window background', async () => {
|
|
934
|
+
const { view, host } = mount('show-sidebar');
|
|
935
|
+
host.setAttribute('style', 'width:900px;height:300px;display:flex');
|
|
936
|
+
await settle();
|
|
937
|
+
const sidebar = view.querySelector('.adw-osv-sidebar') as HTMLElement;
|
|
938
|
+
const content = view.querySelector('.adw-osv-content') as HTMLElement;
|
|
939
|
+
|
|
940
|
+
view.setAttribute('collapsed', '');
|
|
941
|
+
await settle();
|
|
942
|
+
expect(sidebar.classList.contains('overlay-pane')).toBe(true);
|
|
943
|
+
expect(sidebar.classList.contains('sidebar-pane')).toBe(false);
|
|
944
|
+
// Collapsed, libadwaita removes `.content-pane` outright — the
|
|
945
|
+
// content is no longer one pane of two, it is the whole view.
|
|
946
|
+
expect(content.classList.contains('content-pane')).toBe(false);
|
|
947
|
+
expect(bg(sidebar)).toBe(token('--window-bg-color'));
|
|
948
|
+
|
|
949
|
+
// And back: the class follows the state in BOTH directions. A
|
|
950
|
+
// one-way toggle would leave a re-expanded sidebar window-coloured.
|
|
951
|
+
view.removeAttribute('collapsed');
|
|
952
|
+
await settle();
|
|
953
|
+
expect(sidebar.classList.contains('sidebar-pane')).toBe(true);
|
|
954
|
+
expect(bg(sidebar)).toBe(token('--sidebar-bg-color'));
|
|
955
|
+
host.remove();
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
await it('navigation: the pane classes exist while docked and are dropped when collapsed', async () => {
|
|
959
|
+
const host = document.createElement('div');
|
|
960
|
+
host.setAttribute('style', 'width:900px;height:300px;display:flex');
|
|
961
|
+
document.body.appendChild(host);
|
|
962
|
+
host.innerHTML =
|
|
963
|
+
'<adw-navigation-split-view><div slot="sidebar">s</div><div slot="content">c</div></adw-navigation-split-view>';
|
|
964
|
+
const view = host.querySelector('adw-navigation-split-view') as AdwNavigationSplitView;
|
|
965
|
+
await settle();
|
|
966
|
+
const sidebar = view.querySelector('.adw-nsv-sidebar') as HTMLElement;
|
|
967
|
+
const content = view.querySelector('.adw-nsv-content') as HTMLElement;
|
|
968
|
+
|
|
969
|
+
expect(sidebar.classList.contains('sidebar-pane')).toBe(true);
|
|
970
|
+
expect(content.classList.contains('content-pane')).toBe(true);
|
|
971
|
+
expect(bg(sidebar)).toBe(token('--sidebar-bg-color'));
|
|
972
|
+
|
|
973
|
+
// Collapsed, libadwaita builds no pane bins at all: both pages move
|
|
974
|
+
// into one navigation view, so the sidebar is an ordinary full-width
|
|
975
|
+
// page and must stop being sidebar-coloured.
|
|
976
|
+
view.setAttribute('collapsed', '');
|
|
977
|
+
await settle();
|
|
978
|
+
expect(sidebar.classList.contains('sidebar-pane')).toBe(false);
|
|
979
|
+
expect(content.classList.contains('content-pane')).toBe(false);
|
|
980
|
+
expect(bg(sidebar)).not.toBe(token('--sidebar-bg-color'));
|
|
981
|
+
host.remove();
|
|
982
|
+
});
|
|
983
|
+
});
|
|
893
984
|
};
|