@gjsify/adwaita-web 0.35.0 → 0.37.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 +433 -33
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-shortcut-label.spec.d.ts +2 -0
- package/lib/types/breakpoints.d.ts +10 -12
- package/lib/types/elements/adw-about-dialog.d.ts +19 -36
- package/lib/types/elements/adw-action-row.d.ts +9 -12
- package/lib/types/elements/adw-alert-dialog.d.ts +0 -12
- package/lib/types/elements/adw-avatar.d.ts +1 -0
- package/lib/types/elements/adw-bottom-sheet.d.ts +7 -12
- package/lib/types/elements/adw-button-content.d.ts +3 -4
- package/lib/types/elements/adw-button-row.d.ts +1 -1
- package/lib/types/elements/adw-carousel.d.ts +28 -49
- package/lib/types/elements/adw-checks.d.ts +2 -8
- package/lib/types/elements/adw-combo-row.d.ts +6 -6
- package/lib/types/elements/adw-data-grid.d.ts +5 -10
- package/lib/types/elements/adw-drop-down.d.ts +3 -11
- package/lib/types/elements/adw-entry-row.d.ts +20 -23
- package/lib/types/elements/adw-icon.d.ts +2 -4
- package/lib/types/elements/adw-inline-view-switcher.d.ts +18 -31
- package/lib/types/elements/adw-navigation-split-view.d.ts +7 -12
- package/lib/types/elements/adw-navigation-view.d.ts +2 -10
- package/lib/types/elements/adw-overlay-split-view.d.ts +28 -52
- package/lib/types/elements/adw-password-entry-row.d.ts +4 -5
- package/lib/types/elements/adw-popover.d.ts +2 -7
- package/lib/types/elements/adw-preferences-dialog.d.ts +21 -34
- package/lib/types/elements/adw-preferences-group.d.ts +12 -14
- package/lib/types/elements/adw-progress-bar.d.ts +3 -4
- package/lib/types/elements/adw-shortcut-label.d.ts +20 -0
- package/lib/types/elements/adw-sidebar.d.ts +5 -10
- package/lib/types/elements/adw-spinner.d.ts +3 -5
- package/lib/types/elements/adw-split-button.d.ts +6 -16
- package/lib/types/elements/adw-switch-row.d.ts +3 -3
- package/lib/types/elements/adw-tab-view.d.ts +16 -26
- package/lib/types/elements/adw-toast-overlay.d.ts +8 -13
- package/lib/types/elements/adw-view-stack.d.ts +7 -17
- package/lib/types/elements/adw-view-switcher-bar.d.ts +4 -8
- package/lib/types/elements/adw-view-switcher.d.ts +18 -38
- package/lib/types/elements/adw-wrap-box.d.ts +7 -17
- package/lib/types/elements/view-switcher-dom.d.ts +10 -13
- package/lib/types/index.d.ts +1 -0
- package/lib/types/source-view/hex.d.ts +7 -13
- package/lib/types/style-classes.spec.d.ts +11 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +6 -6
- package/scss/_about_dialog.scss +3 -2
- package/scss/_action_row.scss +33 -0
- package/scss/_avatar.scss +12 -0
- package/scss/_button.scss +44 -22
- package/scss/_card.scss +11 -8
- package/scss/_checks.scss +2 -4
- package/scss/_dialog.scss +3 -2
- package/scss/_headerbar.scss +23 -0
- package/scss/_popover.scss +8 -4
- package/scss/_preferences.scss +7 -7
- package/scss/_progress_bar.scss +9 -6
- package/scss/_reset.scss +1 -1
- package/scss/_shortcut_label.scss +80 -0
- package/scss/_sidebar.scss +57 -0
- package/scss/_status_page.scss +20 -0
- package/scss/_style_classes.scss +407 -0
- package/scss/_switch.scss +4 -3
- package/scss/_variables.scss +25 -0
- package/scss/adwaita-skin.scss +12 -0
- package/src/adw-about-dialog.spec.ts +34 -49
- package/src/adw-action-rows.spec.ts +25 -33
- package/src/adw-avatar.spec.ts +51 -20
- package/src/adw-banner.spec.ts +5 -8
- package/src/adw-button-content.spec.ts +9 -12
- package/src/adw-button-row.spec.ts +2 -4
- package/src/adw-carousel.spec.ts +40 -53
- package/src/adw-checks.spec.ts +36 -47
- package/src/adw-drop-down.spec.ts +25 -32
- package/src/adw-header-bar.spec.ts +5 -7
- package/src/adw-icon.spec.ts +23 -32
- package/src/adw-progress-bar.spec.ts +10 -12
- package/src/adw-row-state.spec.ts +9 -10
- package/src/adw-shortcut-label.spec.ts +112 -0
- package/src/adw-sidebar.spec.ts +17 -24
- package/src/adw-switch.spec.ts +11 -17
- package/src/adw-tab-view.spec.ts +7 -10
- package/src/adw-toast-overlay.spec.ts +7 -11
- package/src/adw-view-switcher-bar.spec.ts +10 -14
- package/src/adw-wrap-box.spec.ts +25 -36
- package/src/bottom-sheet.spec.ts +30 -36
- package/src/breakpoints.ts +15 -18
- package/src/chrome.spec.ts +13 -21
- package/src/elements/adw-about-dialog.ts +71 -114
- package/src/elements/adw-action-row.ts +22 -37
- package/src/elements/adw-alert-dialog.ts +25 -50
- package/src/elements/adw-avatar.ts +40 -15
- package/src/elements/adw-banner.ts +14 -18
- package/src/elements/adw-bottom-sheet.ts +31 -52
- package/src/elements/adw-button-content.ts +30 -37
- package/src/elements/adw-button-row.ts +14 -24
- package/src/elements/adw-carousel.ts +87 -148
- package/src/elements/adw-checks.ts +43 -56
- package/src/elements/adw-clamp.ts +8 -9
- package/src/elements/adw-combo-row.ts +17 -25
- package/src/elements/adw-data-grid.ts +26 -38
- package/src/elements/adw-dialog.ts +25 -56
- package/src/elements/adw-drop-down.ts +31 -51
- package/src/elements/adw-entry-row.ts +39 -46
- package/src/elements/adw-expander-row.ts +30 -53
- package/src/elements/adw-icon.ts +30 -53
- package/src/elements/adw-inline-view-switcher.ts +38 -67
- package/src/elements/adw-menu-button.ts +28 -58
- package/src/elements/adw-navigation-split-view.ts +35 -47
- package/src/elements/adw-navigation-view.ts +12 -28
- package/src/elements/adw-overlay-split-view.ts +100 -175
- package/src/elements/adw-password-entry-row.ts +18 -28
- package/src/elements/adw-popover.ts +28 -44
- package/src/elements/adw-preferences-dialog.ts +41 -66
- package/src/elements/adw-preferences-group.ts +33 -46
- package/src/elements/adw-progress-bar.ts +27 -47
- package/src/elements/adw-shortcut-label.ts +138 -0
- package/src/elements/adw-sidebar.ts +31 -39
- package/src/elements/adw-spin-row.ts +7 -14
- package/src/elements/adw-spinner.ts +31 -43
- package/src/elements/adw-split-button.ts +45 -75
- package/src/elements/adw-switch-row.ts +29 -46
- package/src/elements/adw-switch.ts +28 -47
- package/src/elements/adw-tab-view.ts +62 -103
- package/src/elements/adw-toast-overlay.ts +28 -35
- package/src/elements/adw-toggle-group.ts +9 -16
- package/src/elements/adw-view-stack.ts +32 -51
- package/src/elements/adw-view-switcher-bar.ts +26 -50
- package/src/elements/adw-view-switcher.ts +60 -110
- package/src/elements/adw-window-title.ts +4 -4
- package/src/elements/adw-wrap-box.ts +33 -59
- package/src/elements/view-switcher-dom.ts +15 -22
- package/src/entry-rows.spec.ts +18 -24
- package/src/index.ts +13 -15
- package/src/navigation-view.spec.ts +7 -10
- package/src/preferences-search.ts +11 -15
- package/src/preferences.spec.ts +13 -15
- package/src/source-view/adw-source-view.ts +6 -19
- package/src/source-view/hex.ts +7 -13
- package/src/split-button.spec.ts +32 -44
- package/src/split-views.spec.ts +83 -149
- package/src/style-classes.spec.ts +181 -0
- package/src/style-isolation.spec.ts +3 -6
- package/src/styles.generated.ts +1 -1
- package/src/tab-view.spec.ts +26 -35
- package/src/test.browser.mts +4 -0
- package/src/view-stack.spec.ts +23 -34
- package/src/view-switcher.spec.ts +56 -84
package/src/chrome.spec.ts
CHANGED
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
// <adw-spinner> and <adw-toolbar-view> — driven by the SAME vectors the
|
|
3
3
|
// NativeScript renderer asserts against (`@gjsify/adwaita-core/conformance`).
|
|
4
4
|
//
|
|
5
|
-
// Each of the three
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// child to nothing, the spinner defaulted to 24px and stroked a 2px ring where
|
|
9
|
-
// Adwaita strokes 3px, and the toolbar view carried none of the four style
|
|
10
|
-
// classes at all. Nothing failed, because nothing compared them.
|
|
5
|
+
// Each of the three answered a question libadwaita had already answered, and answered it
|
|
6
|
+
// differently from the NativeScript port: clamp tightening and `maximum-size="0"`, the
|
|
7
|
+
// spinner's default size and 3px stroke, and the toolbar view's four style classes.
|
|
11
8
|
//
|
|
12
|
-
// Sizes are driven by really resizing a host element and awaiting a real
|
|
13
|
-
//
|
|
14
|
-
// faking one.
|
|
9
|
+
// Sizes are driven by really resizing a host element and awaiting a real ResizeObserver
|
|
10
|
+
// delivery, as `breakpoints.spec.ts` does — never by faking one.
|
|
15
11
|
import { describe, expect, it } from '@gjsify/unit';
|
|
16
12
|
|
|
17
13
|
import { ADW_SPINNER_MIN_SIZE, ADW_SPINNER_TRACK_OPACITY, spinnerGeometry } from '@gjsify/adwaita-core';
|
|
@@ -54,8 +50,8 @@ function mountClamp(available: number): {
|
|
|
54
50
|
const { host, resize } = mountSized(available);
|
|
55
51
|
const clamp = document.createElement('adw-clamp');
|
|
56
52
|
const child = document.createElement('div');
|
|
57
|
-
// A bare block child fills the clamp and is capped by the max-width the
|
|
58
|
-
//
|
|
53
|
+
// A bare block child fills the clamp and is capped by the max-width the element
|
|
54
|
+
// writes — the shape every story uses.
|
|
59
55
|
child.textContent = 'clamped';
|
|
60
56
|
clamp.appendChild(child);
|
|
61
57
|
host.appendChild(clamp);
|
|
@@ -96,9 +92,8 @@ function mountToolbarView(topBarHeight: number, bottomBarHeight: number): { host
|
|
|
96
92
|
|
|
97
93
|
export const AdwChromeTest = async () => {
|
|
98
94
|
await describe('adw-clamp allocation (AdwClampLayout conformance vectors)', async () => {
|
|
99
|
-
// The browser resolves the child's own minimum through the normal
|
|
100
|
-
//
|
|
101
|
-
// describe what this element can be held to.
|
|
95
|
+
// The browser resolves the child's own minimum through the normal `min-width`
|
|
96
|
+
// cascade, so only rows with a zero child minimum describe this element.
|
|
102
97
|
const vectors = CLAMP_ALLOCATE_VECTORS.filter((v) => v.params.childMin === 0);
|
|
103
98
|
|
|
104
99
|
for (const { availableSize, params, childSize, sizeClass, offset, rule } of vectors) {
|
|
@@ -110,7 +105,7 @@ export const AdwChromeTest = async () => {
|
|
|
110
105
|
|
|
111
106
|
expect(clampedWidth(child)).toBe(childSize);
|
|
112
107
|
expect(sizeClassOf(child)).toBe(sizeClass);
|
|
113
|
-
// `margin-inline: auto` splits the remainder evenly
|
|
108
|
+
// `margin-inline: auto` splits the remainder evenly where libadwaita
|
|
114
109
|
// truncates, so the two can differ by half a pixel.
|
|
115
110
|
const leading = child.getBoundingClientRect().left - clamp.getBoundingClientRect().left;
|
|
116
111
|
expect(Math.abs(leading - offset) <= 1).toBe(true);
|
|
@@ -120,8 +115,7 @@ export const AdwChromeTest = async () => {
|
|
|
120
115
|
}
|
|
121
116
|
|
|
122
117
|
await it('follows the viewport instead of pinning the child to the maximum', async () => {
|
|
123
|
-
//
|
|
124
|
-
// hand the child ALL of the available width, not the cap.
|
|
118
|
+
// A narrow clamp hands the child ALL of the available width, not the cap.
|
|
125
119
|
const { host, clamp, child, resize } = mountClamp(1000);
|
|
126
120
|
await settle();
|
|
127
121
|
expect(clampedWidth(child)).toBe(600);
|
|
@@ -132,8 +126,6 @@ export const AdwChromeTest = async () => {
|
|
|
132
126
|
});
|
|
133
127
|
|
|
134
128
|
await it('honours tightening-threshold, which the element used to ignore', async () => {
|
|
135
|
-
// The storybook has exposed this control all along and only the GTK
|
|
136
|
-
// pane responded to it.
|
|
137
129
|
const { host, clamp, child } = mountClamp(700);
|
|
138
130
|
clamp.setAttribute('maximum-size', '600');
|
|
139
131
|
clamp.setAttribute('tightening-threshold', '400');
|
|
@@ -323,7 +315,7 @@ export const AdwChromeTest = async () => {
|
|
|
323
315
|
|
|
324
316
|
await it('KEEPS SPINNING under reduced motion — a frozen busy indicator reads as a hang', () => {
|
|
325
317
|
// libadwaita opts the spinner out of the animation setting on purpose
|
|
326
|
-
|
|
318
|
+
//. The old stylesheet had
|
|
327
319
|
// `@media (prefers-reduced-motion: reduce) { animation: none }`, so
|
|
328
320
|
// this asserts the ABSENCE of any CSS animation to switch off: the
|
|
329
321
|
// arc is driven per frame from JS and cannot be disabled by a query.
|
|
@@ -345,7 +337,7 @@ export const AdwChromeTest = async () => {
|
|
|
345
337
|
expect(arc.getAttribute('stroke-dashoffset')).not.toBe(first);
|
|
346
338
|
|
|
347
339
|
// Unmapping removes it from the shared ticker — `widget_map_cb`
|
|
348
|
-
//
|
|
340
|
+
// is what plays the animation, so
|
|
349
341
|
// an off-screen spinner burns nothing.
|
|
350
342
|
spinner.remove();
|
|
351
343
|
const parked = arc.getAttribute('stroke-dashoffset');
|
|
@@ -1,65 +1,52 @@
|
|
|
1
|
-
// <adw-about-dialog> — The standard Adwaita "About" dialog (the web counterpart
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// <adw-about-dialog> — The standard Adwaita "About" dialog (the web counterpart of
|
|
2
|
+
// Adw.AboutDialog): a modal AdwDialog (full-cover scrim + centred, scrollable
|
|
3
|
+
// floating sheet) hosting a navigation view, whose main page shows the app icon,
|
|
4
|
+
// name, developer name and a version pill, followed by up to three preference
|
|
5
|
+
// groups of rows that link out or push a subpage.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// main page is scrolled (mirroring AdwAboutDialog's update_headerbar_cb).
|
|
7
|
+
// Presented imperatively — `present()` (or setting `open`) reveals it; Escape, a
|
|
8
|
+
// scrim click, the header close button or `close()` dismisses it. The header title
|
|
9
|
+
// fades in once the main page is scrolled (`update_headerbar_cb`).
|
|
11
10
|
//
|
|
12
11
|
// WHICH PAGE A ROW IS ON IS NOT A LAYOUT CHOICE — it is `update_details` and
|
|
13
|
-
// `update_support
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// invented fallbacks GTK does not have — "Application" for a missing name, a
|
|
20
|
-
// generic executable glyph for a missing icon, and an "About <app>" title on top
|
|
21
|
-
// of an "About <app>" label. All four derivations now come from
|
|
22
|
-
// `@gjsify/adwaita-core`, which holds them once for both renderers (ADR 0004)
|
|
23
|
-
// and is held to `@gjsify/adwaita-core/conformance`.
|
|
12
|
+
// `update_support`. `website` is the one input libadwaita deliberately leaves OUT
|
|
13
|
+
// of the details predicate, so a dialog whose only extra is a website must not grow
|
|
14
|
+
// a Details subpage holding a single link; and there are no fallbacks GTK does not
|
|
15
|
+
// have (no "Application" for a missing name, no generic glyph for a missing icon).
|
|
16
|
+
// All four derivations come from `@gjsify/adwaita-core` (ADR 0004), which holds them
|
|
17
|
+
// once for both renderers and is held to `@gjsify/adwaita-core/conformance`.
|
|
24
18
|
//
|
|
25
19
|
// Properties / attributes (all reflected, mirroring the AdwAboutDialog GObject
|
|
26
20
|
// properties of the same name, hyphenated):
|
|
27
21
|
// application-name the application's display name (shown as a title-1)
|
|
28
|
-
// application-icon a symbolic icon name (with or without -symbolic)
|
|
29
|
-
//
|
|
22
|
+
// application-icon a symbolic icon name (with or without -symbolic); absent
|
|
23
|
+
// one, no icon is drawn
|
|
30
24
|
// developer-name the developer / vendor line below the name
|
|
31
25
|
// version the version, shown as a clickable pill
|
|
32
|
-
// comments a longer description (
|
|
33
|
-
// website the
|
|
34
|
-
//
|
|
26
|
+
// comments a longer description (Details page)
|
|
27
|
+
// website the website URL — a Website link row, on the MAIN page
|
|
28
|
+
// unless the Details page has other content
|
|
35
29
|
// support-url a support-forum URL (a main-page Support Questions row)
|
|
36
30
|
// issue-url an issue-tracker URL (a main-page Report an Issue row)
|
|
37
|
-
// copyright the copyright line (
|
|
38
|
-
// license the license text/name (
|
|
39
|
-
//
|
|
31
|
+
// copyright the copyright line (Legal page)
|
|
32
|
+
// license the license text/name (Legal page); with a `license-url`
|
|
33
|
+
// the name becomes a link
|
|
40
34
|
// license-url a URL the license name links to
|
|
41
35
|
// open (boolean) whether the dialog is presented
|
|
42
36
|
//
|
|
43
37
|
// List-valued credits are set via properties (string arrays), mirroring the
|
|
44
|
-
// AdwAboutDialog `developers` / `designers` / `artists` / `documenters`
|
|
45
|
-
//
|
|
46
|
-
//
|
|
38
|
+
// AdwAboutDialog `developers` / `designers` / `artists` / `documenters` properties
|
|
39
|
+
// — entries may be `Name`, `Name <email>` or `Name https://url`, parsed by the
|
|
40
|
+
// core's `parseCreditPerson` (`parse_person`).
|
|
47
41
|
//
|
|
48
|
-
// NOT implemented here
|
|
49
|
-
//
|
|
50
|
-
// the
|
|
51
|
-
// `translator-credits` and the Acknowledgements page. The core covers all of
|
|
52
|
-
// them; adopting them is a feature, not a fidelity fix.
|
|
42
|
+
// NOT implemented here, so the core derivations see them empty: `release-notes` +
|
|
43
|
+
// the What's New page, `debug-info` + the Troubleshooting page, `add_link`,
|
|
44
|
+
// `add_credit_section`, `translator-credits` and the Acknowledgements page.
|
|
53
45
|
//
|
|
54
|
-
// Events (CustomEvent, bubbles):
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// `activate-link` (detail = { uri }, CANCELABLE) when a link is activated —
|
|
59
|
-
// mirrors AdwAboutDialog::activate-link, a boolean signal with the
|
|
60
|
-
// `true_handled` accumulator (:2093-2103): a handler that returns TRUE
|
|
61
|
-
// suppresses the default navigation (:429-437). `preventDefault()` is the
|
|
62
|
-
// web spelling of returning TRUE.
|
|
46
|
+
// Events (CustomEvent, bubbles): `notify::open` (detail `{ open }`), `closed`, and
|
|
47
|
+
// `activate-link` (detail `{ uri }`, CANCELABLE — the signal's `true_handled`
|
|
48
|
+
// accumulator means "a handler returned TRUE suppresses the default navigation",
|
|
49
|
+
// which is what `preventDefault()` spells).
|
|
63
50
|
//
|
|
64
51
|
// Reference: refs/libadwaita/src/adw-about-dialog.c (AdwAboutDialog behaviour)
|
|
65
52
|
// Reference: refs/libadwaita/src/adw-about-dialog.ui (navigation page tree)
|
|
@@ -120,8 +107,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
120
107
|
];
|
|
121
108
|
}
|
|
122
109
|
|
|
123
|
-
// --- Reflected scalar properties ---
|
|
124
|
-
|
|
125
110
|
get applicationName(): string {
|
|
126
111
|
return this.getAttribute('application-name') ?? '';
|
|
127
112
|
}
|
|
@@ -210,7 +195,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
210
195
|
this.setAttribute('license-url', value);
|
|
211
196
|
}
|
|
212
197
|
|
|
213
|
-
/** Whether the dialog is presented. */
|
|
214
198
|
get open(): boolean {
|
|
215
199
|
return this.hasAttribute('open');
|
|
216
200
|
}
|
|
@@ -220,8 +204,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
220
204
|
else this.removeAttribute('open');
|
|
221
205
|
}
|
|
222
206
|
|
|
223
|
-
// --- List-valued credit properties (no attribute form) ---
|
|
224
|
-
|
|
225
207
|
get developers(): string[] {
|
|
226
208
|
return this._developers;
|
|
227
209
|
}
|
|
@@ -272,19 +254,17 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
272
254
|
if (this._initialized) return;
|
|
273
255
|
this._initialized = true;
|
|
274
256
|
|
|
275
|
-
// The full-cover modal scrim — clicking it dismisses the dialog.
|
|
276
257
|
this._scrimEl = document.createElement('div');
|
|
277
258
|
this._scrimEl.className = 'adw-about-dialog-scrim';
|
|
278
259
|
this._scrimEl.addEventListener('click', () => this.close());
|
|
279
260
|
|
|
280
|
-
// The centred floating sheet.
|
|
281
261
|
this._sheetEl = document.createElement('div');
|
|
282
262
|
this._sheetEl.className = 'adw-about-dialog-sheet';
|
|
283
263
|
this._sheetEl.setAttribute('role', 'dialog');
|
|
284
264
|
this._sheetEl.setAttribute('aria-modal', 'true');
|
|
285
|
-
// AdwDialog:title, whose template default is the bare word
|
|
286
|
-
//
|
|
287
|
-
//
|
|
265
|
+
// AdwDialog:title, whose template default is the bare word. The application
|
|
266
|
+
// name is announced by the title-1 label inside, exactly as the header
|
|
267
|
+
// revealer shows it separately in GTK.
|
|
288
268
|
this._sheetEl.setAttribute('aria-label', ADW_ABOUT_DIALOG_LABELS.dialogTitle);
|
|
289
269
|
|
|
290
270
|
this.replaceChildren(this._scrimEl, this._sheetEl);
|
|
@@ -337,23 +317,18 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
337
317
|
}
|
|
338
318
|
|
|
339
319
|
/**
|
|
340
|
-
* Whether the Legal page has anything on it.
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
* is set, unknown otherwise", which is what `adw_about_dialog_set_license`
|
|
345
|
-
* does to the type anyway (:3472).
|
|
320
|
+
* Whether the Legal page has anything on it. This element's licence model is the
|
|
321
|
+
* simplified one — a name plus an optional URL — so it maps onto `GtkLicense` as
|
|
322
|
+
* "custom text when a licence is set, unknown otherwise", which is what
|
|
323
|
+
* `adw_about_dialog_set_license` does to the type anyway.
|
|
346
324
|
*/
|
|
347
325
|
private _hasLegal(): boolean {
|
|
348
326
|
const licenseType = this.license.length > 0 ? GTK_LICENSE.CUSTOM : GTK_LICENSE.UNKNOWN;
|
|
349
327
|
return legalSectionVisible(this.copyright, licenseType, this.license);
|
|
350
328
|
}
|
|
351
329
|
|
|
352
|
-
/** Rebuild the sheet contents from the current attributes / credit lists. */
|
|
353
330
|
private _render(): void {
|
|
354
331
|
const sections = this._creditsSections();
|
|
355
|
-
// The four inputs this element has no API for stay empty: `debug-info`,
|
|
356
|
-
// `release-notes`, `add_link` and the acknowledgements page.
|
|
357
332
|
const visibility = aboutDialogVisibility({
|
|
358
333
|
applicationIcon: this.applicationIcon,
|
|
359
334
|
applicationName: this.applicationName,
|
|
@@ -367,12 +342,11 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
367
342
|
hasLegal: this._hasLegal(),
|
|
368
343
|
});
|
|
369
344
|
|
|
370
|
-
// The navigation view (main page + subpages) lives inside the sheet.
|
|
371
345
|
this._navView = document.createElement('adw-navigation-view');
|
|
372
346
|
this._navView.append(this._buildMainPage(visibility));
|
|
373
347
|
|
|
374
348
|
// The Details page exists exactly when its row does — `details_row` is
|
|
375
|
-
// `has_comments || show_links
|
|
349
|
+
// `has_comments || show_links`, i.e. "the page has content".
|
|
376
350
|
if (visibility.detailsRow) this._navView.append(this._buildDetailsPage(visibility));
|
|
377
351
|
if (visibility.creditsRow) this._navView.append(this._buildCreditsPage(sections));
|
|
378
352
|
if (visibility.legalRow) this._navView.append(this._buildLegalPage());
|
|
@@ -385,10 +359,8 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
385
359
|
|
|
386
360
|
/**
|
|
387
361
|
* A navigation page wrapping a header bar (with the close button) + content.
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* because its page title is the dialog's ("About", .ui:19) while its header
|
|
391
|
-
* shows the application name (.ui:30).
|
|
362
|
+
* `headerTitle` defaults to the page title; the main page overrides it, because its
|
|
363
|
+
* page title is the dialog's ("About") while its header shows the application name.
|
|
392
364
|
*/
|
|
393
365
|
private _buildPage(
|
|
394
366
|
tag: string,
|
|
@@ -410,9 +382,10 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
410
382
|
header.setAttribute('title', headerTitle);
|
|
411
383
|
|
|
412
384
|
if (showClose) {
|
|
413
|
-
// The close button — drawn with a CSS "×" glyph
|
|
414
|
-
//
|
|
415
|
-
//
|
|
385
|
+
// The close button — drawn with a CSS "×" glyph, the same approach as
|
|
386
|
+
// adw-tab-view's close affordance: `window-close` has no mask class,
|
|
387
|
+
// because it is not in the ICONS map in `scripts/build-scss.mjs` that
|
|
388
|
+
// generates them (`@gjsify/adwaita-icons` does export the SVG).
|
|
416
389
|
const close = document.createElement('button');
|
|
417
390
|
close.type = 'button';
|
|
418
391
|
close.className = 'adw-button flat circular adw-about-dialog-close';
|
|
@@ -422,8 +395,8 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
422
395
|
const end = (header as { endSection?: HTMLElement | null }).endSection ?? null;
|
|
423
396
|
if (end) end.appendChild(close);
|
|
424
397
|
};
|
|
425
|
-
// The header bar builds its sections in its own connectedCallback
|
|
426
|
-
//
|
|
398
|
+
// The header bar builds its sections in its own connectedCallback, so the
|
|
399
|
+
// close button can only be appended after that has run.
|
|
427
400
|
queueMicrotask(endApply);
|
|
428
401
|
}
|
|
429
402
|
|
|
@@ -445,7 +418,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
445
418
|
if (tag === 'main') {
|
|
446
419
|
this._scrollEl = scroll;
|
|
447
420
|
this._mainToolbarEl = toolbar;
|
|
448
|
-
// The main page's header title fades in once the content scrolls.
|
|
449
421
|
toolbar.classList.add('main-page');
|
|
450
422
|
scroll.addEventListener('scroll', () => this._updateHeaderTitle());
|
|
451
423
|
}
|
|
@@ -453,21 +425,19 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
453
425
|
return { page, body, header };
|
|
454
426
|
}
|
|
455
427
|
|
|
456
|
-
/** The main page: icon, name, developer, version pill, then the three groups. */
|
|
457
428
|
private _buildMainPage(visibility: ReturnType<typeof aboutDialogVisibility>): HTMLElement {
|
|
458
429
|
const { page, body } = this._buildPage('main', ADW_ABOUT_DIALOG_LABELS.dialogTitle, true, this.applicationName);
|
|
459
430
|
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
//
|
|
463
|
-
//
|
|
464
|
-
//
|
|
465
|
-
// see `normalizeIconName`.
|
|
431
|
+
// Only when one was given: GTK hides the image outright for an empty icon
|
|
432
|
+
// name, and a generic glyph would show an icon for an application that asked
|
|
433
|
+
// for none. A reverse-DNS application id (`org.gnome.Builder`) is not one CSS
|
|
434
|
+
// token and resolves to no glyph rather than to three stray classes — see
|
|
435
|
+
// `normalizeIconName`.
|
|
466
436
|
if (visibility.appIcon) {
|
|
467
437
|
body.appendChild(createAdwIcon(this.applicationIcon, 'adw-about-dialog-icon'));
|
|
468
438
|
}
|
|
469
439
|
|
|
470
|
-
//
|
|
440
|
+
// No fallback: an unset name means no label.
|
|
471
441
|
if (visibility.appName) {
|
|
472
442
|
const nameEl = document.createElement('span');
|
|
473
443
|
nameEl.className = 'adw-about-dialog-name';
|
|
@@ -475,7 +445,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
475
445
|
body.appendChild(nameEl);
|
|
476
446
|
}
|
|
477
447
|
|
|
478
|
-
// Developer / vendor.
|
|
479
448
|
if (visibility.developerName) {
|
|
480
449
|
const devEl = document.createElement('span');
|
|
481
450
|
devEl.className = 'adw-about-dialog-developer';
|
|
@@ -483,7 +452,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
483
452
|
body.appendChild(devEl);
|
|
484
453
|
}
|
|
485
454
|
|
|
486
|
-
// Version pill.
|
|
487
455
|
if (visibility.version) {
|
|
488
456
|
const versionEl = document.createElement('span');
|
|
489
457
|
versionEl.className = 'adw-about-dialog-version';
|
|
@@ -491,10 +459,9 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
491
459
|
body.appendChild(versionEl);
|
|
492
460
|
}
|
|
493
461
|
|
|
494
|
-
// Three separate preference groups, as in the template
|
|
495
|
-
//
|
|
496
|
-
//
|
|
497
|
-
// consecutive `.adw-about-dialog-rows` apart for exactly this.
|
|
462
|
+
// Three separate preference groups, as in the template (details_group,
|
|
463
|
+
// support_group, credits_legal_group) — groups, not one list, and the
|
|
464
|
+
// stylesheet already spaces consecutive `.adw-about-dialog-rows` apart.
|
|
498
465
|
const detailsGroupRows: HTMLElement[] = [];
|
|
499
466
|
if (visibility.detailsRow) {
|
|
500
467
|
detailsGroupRows.push(this._buildNavRow(rowLabel('detailsRow'), 'details'));
|
|
@@ -523,12 +490,10 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
523
490
|
}
|
|
524
491
|
|
|
525
492
|
/**
|
|
526
|
-
* One `AdwPreferencesGroup` in its spacing wrapper.
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
* sections pass `null`, because the template has no id for them: they are
|
|
531
|
-
* built one per section at runtime (:548-549).
|
|
493
|
+
* One `AdwPreferencesGroup` in its spacing wrapper. `data-group` carries the
|
|
494
|
+
* template's widget id so a test — and a reader — can tell the named groups apart;
|
|
495
|
+
* nothing styles off it. The credits sections pass `null`, because the template has
|
|
496
|
+
* no id for them: they are built one per section at runtime.
|
|
532
497
|
*/
|
|
533
498
|
private _buildGroup(id: string | null, rows: HTMLElement[], title?: string): HTMLElement {
|
|
534
499
|
const group = document.createElement('adw-preferences-group');
|
|
@@ -542,7 +507,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
542
507
|
return wrap;
|
|
543
508
|
}
|
|
544
509
|
|
|
545
|
-
/** An activatable row that pushes a subpage, with a trailing go-next chevron. */
|
|
546
510
|
private _buildNavRow(title: string, tag: string): HTMLElement {
|
|
547
511
|
const row = document.createElement('adw-action-row');
|
|
548
512
|
row.setAttribute('title', title);
|
|
@@ -561,20 +525,17 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
561
525
|
}
|
|
562
526
|
|
|
563
527
|
/**
|
|
564
|
-
* Emit `activate-link` and navigate unless a handler took over.
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
* suppresses it — which is what `preventDefault()` on a cancelable event
|
|
570
|
-
* means, and why `dispatchEvent`'s return value is the gate here.
|
|
528
|
+
* Emit `activate-link` and navigate unless a handler took over. The GObject signal
|
|
529
|
+
* is `BOOLEAN__STRING` with `g_signal_accumulator_true_handled` and its default
|
|
530
|
+
* handler returns `GDK_EVENT_PROPAGATE` ("not handled, do the default"); a handler
|
|
531
|
+
* returning TRUE suppresses it, which is what `preventDefault()` on a cancelable
|
|
532
|
+
* event means — hence the gate on `dispatchEvent`'s return value.
|
|
571
533
|
*/
|
|
572
534
|
private _activateLink(uri: string): void {
|
|
573
535
|
const event = new CustomEvent('activate-link', { bubbles: true, cancelable: true, detail: { uri } });
|
|
574
536
|
if (this.dispatchEvent(event)) window.open(uri, '_blank', 'noopener,noreferrer');
|
|
575
537
|
}
|
|
576
538
|
|
|
577
|
-
/** The Details page: comments + the links group (website + future custom links). */
|
|
578
539
|
private _buildDetailsPage(visibility: ReturnType<typeof aboutDialogVisibility>): HTMLElement {
|
|
579
540
|
const { page, body } = this._buildPage('details', ADW_ABOUT_DIALOG_LABELS.detailsPage, false);
|
|
580
541
|
|
|
@@ -596,7 +557,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
596
557
|
return page;
|
|
597
558
|
}
|
|
598
559
|
|
|
599
|
-
/** A link row that opens a URL in a new tab and emits `activate-link`. */
|
|
600
560
|
private _buildLinkRow(title: string, uri: string): HTMLElement {
|
|
601
561
|
const row = document.createElement('adw-action-row');
|
|
602
562
|
row.setAttribute('title', title);
|
|
@@ -612,7 +572,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
612
572
|
return row;
|
|
613
573
|
}
|
|
614
574
|
|
|
615
|
-
/** The Credits page: one group per section the core assembled. */
|
|
616
575
|
private _buildCreditsPage(sections: ReturnType<typeof creditsSections>): HTMLElement {
|
|
617
576
|
const { page, body } = this._buildPage('credits', ADW_ABOUT_DIALOG_LABELS.creditsPage, false);
|
|
618
577
|
|
|
@@ -625,11 +584,10 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
625
584
|
}
|
|
626
585
|
|
|
627
586
|
/**
|
|
628
|
-
* A credit row — a plain title, or a link row when the entry carries a URI.
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
* an
|
|
632
|
-
* pointer, :562) and still produces an `AdwLinkRow`, to `mailto:`.
|
|
587
|
+
* A credit row — a plain title, or a link row when the entry carries a URI. The gate
|
|
588
|
+
* is `link !== null`, not the URI's truthiness: `"Ada <>"` parses to an EMPTY link,
|
|
589
|
+
* which is still a link in the C (`if (link)` tests the pointer) and still produces
|
|
590
|
+
* an `AdwLinkRow`, to `mailto:`.
|
|
633
591
|
*/
|
|
634
592
|
private _buildCreditRow(person: AdwCreditPerson): HTMLElement {
|
|
635
593
|
const row = document.createElement('adw-action-row');
|
|
@@ -648,7 +606,6 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
648
606
|
return row;
|
|
649
607
|
}
|
|
650
608
|
|
|
651
|
-
/** The Legal page: copyright + license text. */
|
|
652
609
|
private _buildLegalPage(): HTMLElement {
|
|
653
610
|
const { page, body } = this._buildPage('legal', ADW_ABOUT_DIALOG_LABELS.legalPage, false);
|
|
654
611
|
|
|
@@ -664,7 +621,7 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
664
621
|
license.className = 'adw-about-dialog-license';
|
|
665
622
|
if (this.licenseUrl) {
|
|
666
623
|
// GTK connects the legal label's `activate-link` to the same
|
|
667
|
-
// handler as the rows
|
|
624
|
+
// handler as the rows, so this link is cancelable too.
|
|
668
625
|
const link = document.createElement('a');
|
|
669
626
|
link.href = this.licenseUrl;
|
|
670
627
|
link.rel = 'noopener noreferrer';
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
// <adw-action-row> —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// the row forwards its activation to, and whose sensitivity drives whether the
|
|
6
|
-
// row is activatable at all.
|
|
7
|
-
// Slots: slot="prefix" (icons/widgets before the text), slot="suffix" (controls
|
|
8
|
-
// after the text — switches, buttons, value labels).
|
|
9
|
-
// Events: `activated` (CustomEvent) when an `activatable` row is clicked.
|
|
1
|
+
// <adw-action-row> — a boxed-list row with a title, optional subtitle and prefix /
|
|
2
|
+
// suffix widget slots; the most fundamental Adwaita row type. `slot="prefix"` holds
|
|
3
|
+
// icons/widgets before the text, `slot="suffix"` the controls after it, and an
|
|
4
|
+
// `activatable` row emits `activated` on click.
|
|
10
5
|
//
|
|
11
|
-
// The LABEL VISIBILITY rule and the activatable-widget coupling are HEADLESS and
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// `@gjsify/adwaita-nativescript` composes the same state, so both ports share one
|
|
15
|
-
// behaviour.
|
|
6
|
+
// The LABEL VISIBILITY rule and the activatable-widget coupling are HEADLESS and live
|
|
7
|
+
// in `@gjsify/adwaita-core` (ADR 0004) as {@link ActionRowState}; this element keeps
|
|
8
|
+
// only the DOM render half.
|
|
16
9
|
//
|
|
17
10
|
// Reference: refs/adwaita-web/adwaita-web/docs/widgets/actionrow.md
|
|
18
11
|
// Reference: refs/libadwaita/src/adw-action-row.c, adw-action-row.ui
|
|
@@ -67,10 +60,9 @@ export class AdwActionRow extends HTMLElement {
|
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
/**
|
|
70
|
-
* Set the activatable widget. Its sensitivity is copied into `activatable`
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* that surprises: clearing the widget LEAVES the row activatable (C:709).
|
|
63
|
+
* Set the activatable widget. Its sensitivity is copied into `activatable` right
|
|
64
|
+
* away and then tracked, as libadwaita's `sensitive` → `activatable` binding does —
|
|
65
|
+
* including the surprising part: clearing the widget LEAVES the row activatable.
|
|
74
66
|
*/
|
|
75
67
|
set activatableWidget(widget: HTMLElement | null) {
|
|
76
68
|
if (!this._state.setActivatableWidget(widget, widget ? isSensitive(widget) : true)) return;
|
|
@@ -85,13 +77,9 @@ export class AdwActionRow extends HTMLElement {
|
|
|
85
77
|
|
|
86
78
|
connectedCallback() {
|
|
87
79
|
if (this._initialized) {
|
|
88
|
-
// Re-entering a document
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
// becoming insensitive — the same shape that broke the overlay
|
|
92
|
-
// split view's ResizeObserver and both view switchers' page
|
|
93
|
-
// observers. Anything torn down on the way out has to be rebuilt
|
|
94
|
-
// on the way back in.
|
|
80
|
+
// Re-entering a document: `disconnectedCallback` dropped the sensitivity
|
|
81
|
+
// observer, so it has to be rebuilt here or a MOVED row is permanently blind
|
|
82
|
+
// to its activatable widget becoming insensitive.
|
|
95
83
|
this._observeSensitivity(this._state.activatableWidget);
|
|
96
84
|
return;
|
|
97
85
|
}
|
|
@@ -117,8 +105,8 @@ export class AdwActionRow extends HTMLElement {
|
|
|
117
105
|
for (const child of suffixChildren) this._suffixEl.appendChild(child);
|
|
118
106
|
|
|
119
107
|
this.replaceChildren(this._prefixEl, textEl, this._suffixEl);
|
|
120
|
-
//
|
|
121
|
-
//
|
|
108
|
+
// `attributeChangedCallback` was guarded until now, so a parsed row would
|
|
109
|
+
// otherwise start with a stale state.
|
|
122
110
|
this._adoptAttributes();
|
|
123
111
|
this._render();
|
|
124
112
|
|
|
@@ -144,15 +132,13 @@ export class AdwActionRow extends HTMLElement {
|
|
|
144
132
|
}
|
|
145
133
|
|
|
146
134
|
/**
|
|
147
|
-
* `adw_action_row_activate_real
|
|
148
|
-
*
|
|
135
|
+
* `adw_action_row_activate_real`: forward the activation to the activatable widget,
|
|
136
|
+
* then emit `activated`.
|
|
149
137
|
*
|
|
150
|
-
* A click that ORIGINATED inside the activatable widget does not activate the
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* suffixes (C:120-137). It is also what keeps the forwarding from looping —
|
|
155
|
-
* the synthetic click dispatched below bubbles straight back into this same
|
|
138
|
+
* A click that ORIGINATED inside the activatable widget does not activate the row at
|
|
139
|
+
* all — no forwarding, no `activated`. That is GTK's answer too: the widget claims
|
|
140
|
+
* the gesture, so `GtkListBox` never emits `row-activated`. It is also what keeps the
|
|
141
|
+
* forwarding from looping — the synthetic click below bubbles back into this same
|
|
156
142
|
* listener, and without the guard one activation emitted `activated` twice.
|
|
157
143
|
*/
|
|
158
144
|
private _onClick(event: Event) {
|
|
@@ -188,8 +174,7 @@ export class AdwActionRow extends HTMLElement {
|
|
|
188
174
|
private _render() {
|
|
189
175
|
const { title, titleVisible, subtitle, subtitleVisible } = this._state.state;
|
|
190
176
|
this._titleEl.textContent = title;
|
|
191
|
-
// `string_is_not_empty` applies to the TITLE as much as to the subtitle
|
|
192
|
-
// (adw-action-row.ui:49-53) — an empty title used to keep its line here.
|
|
177
|
+
// `string_is_not_empty` applies to the TITLE as much as to the subtitle.
|
|
193
178
|
this._titleEl.hidden = !titleVisible;
|
|
194
179
|
this._subtitleEl.textContent = subtitle;
|
|
195
180
|
this._subtitleEl.hidden = !subtitleVisible;
|