@gjsify/adwaita-web 0.44.0 → 0.46.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/README.md +8 -6
- package/dist/adwaita-web.css +96 -96
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/elements/adw-entry-row.d.ts +2 -2
- package/lib/types/elements/adw-expander-row.d.ts +1 -1
- package/lib/types/elements/adw-header-bar.d.ts +16 -8
- package/lib/types/elements/adw-split-button.d.ts +1 -1
- package/lib/types/elements/adw-switch-row.d.ts +1 -1
- package/lib/types/elements/adw-wrap-box.d.ts +1 -1
- package/lib/types/elements/{adw-checks.d.ts → checks.d.ts} +9 -2
- package/lib/types/elements/{adw-button.d.ts → gtk-button.d.ts} +1 -1
- package/lib/types/elements/{adw-drop-down.d.ts → gtk-drop-down.d.ts} +6 -6
- package/lib/types/elements/{adw-entry.d.ts → gtk-entry.d.ts} +1 -1
- package/lib/types/elements/{adw-icon.d.ts → gtk-image.d.ts} +2 -2
- package/lib/types/elements/{adw-menu-button.d.ts → gtk-menu-button.d.ts} +13 -4
- package/lib/types/elements/{adw-popover.d.ts → gtk-popover.d.ts} +9 -9
- package/lib/types/elements/{adw-progress-bar.d.ts → gtk-progress-bar.d.ts} +1 -1
- package/lib/types/elements/{adw-switch.d.ts → gtk-switch.d.ts} +2 -2
- package/lib/types/elements/view-switcher-dom.d.ts +4 -4
- package/lib/types/exported-elements.d.ts +10 -0
- package/lib/types/gtk-button.spec.d.ts +1 -0
- package/lib/types/gtk-drop-down.spec.d.ts +1 -0
- package/lib/types/gtk-entry.spec.d.ts +1 -0
- package/lib/types/gtk-image.spec.d.ts +1 -0
- package/lib/types/gtk-menu-button.spec.d.ts +1 -0
- package/lib/types/gtk-progress-bar.spec.d.ts +1 -0
- package/lib/types/gtk-switch.spec.d.ts +1 -0
- package/lib/types/icon-registry.d.ts +2 -2
- package/lib/types/index.d.ts +13 -51
- package/lib/types/namespace/adw.d.ts +44 -0
- package/lib/types/namespace/gtk.d.ts +9 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/package.json +9 -6
- package/scss/_about_dialog.scss +1 -1
- package/scss/_button.scss +4 -4
- package/scss/_checks.scss +6 -6
- package/scss/_drop_down.scss +3 -3
- package/scss/_entry.scss +3 -3
- package/scss/_expander_row.scss +1 -1
- package/scss/_icon.scss +4 -4
- package/scss/_menu_button.scss +3 -3
- package/scss/_popover.scss +2 -2
- package/scss/_progress_bar.scss +4 -4
- package/scss/_reset.scss +10 -8
- package/scss/_split_button.scss +1 -1
- package/scss/_style_classes.scss +9 -9
- package/scss/_switch.scss +2 -2
- package/scss/_switch_row.scss +1 -1
- package/scss/_toast.scss +1 -1
- package/scss/adwaita-skin.scss +2 -2
- package/src/adw-action-rows.spec.ts +2 -2
- package/src/adw-button-content.spec.ts +1 -1
- package/src/adw-header-bar.spec.ts +9 -4
- package/src/adw-tab-view.spec.ts +71 -0
- package/src/bottom-sheet.spec.ts +2 -2
- package/src/{adw-checks.spec.ts → checks.spec.ts} +11 -11
- package/src/chrome.spec.ts +2 -2
- package/src/connect-lifecycle.spec.ts +10 -7
- package/src/elements/adw-about-dialog.ts +6 -6
- package/src/elements/adw-avatar.ts +4 -4
- package/src/elements/adw-button-content.ts +6 -6
- package/src/elements/adw-button-row.ts +6 -6
- package/src/elements/adw-combo-row.ts +1 -1
- package/src/elements/adw-entry-row.ts +5 -5
- package/src/elements/adw-expander-row.ts +10 -10
- package/src/elements/adw-header-bar.ts +34 -13
- package/src/elements/adw-navigation-view.ts +24 -4
- package/src/elements/adw-password-entry-row.ts +3 -3
- package/src/elements/adw-sidebar.ts +4 -4
- package/src/elements/adw-split-button.ts +14 -14
- package/src/elements/adw-status-page.ts +4 -4
- package/src/elements/adw-switch-row.ts +8 -8
- package/src/elements/adw-tab-view.ts +32 -10
- package/src/elements/adw-toast-overlay.ts +2 -2
- package/src/elements/adw-toggle-group.ts +3 -3
- package/src/elements/adw-view-switcher-bar.ts +3 -3
- package/src/elements/adw-view-switcher.ts +3 -3
- package/src/elements/{adw-checks.ts → checks.ts} +13 -6
- package/src/elements/{adw-button.ts → gtk-button.ts} +6 -6
- package/src/elements/{adw-drop-down.ts → gtk-drop-down.ts} +18 -18
- package/src/elements/{adw-entry.ts → gtk-entry.ts} +4 -4
- package/src/elements/{adw-icon.ts → gtk-image.ts} +5 -5
- package/src/elements/{adw-menu-button.ts → gtk-menu-button.ts} +27 -18
- package/src/elements/{adw-popover.ts → gtk-popover.ts} +18 -18
- package/src/elements/{adw-progress-bar.ts → gtk-progress-bar.ts} +5 -5
- package/src/elements/{adw-switch.ts → gtk-switch.ts} +4 -4
- package/src/elements/view-switcher-dom.ts +5 -5
- package/src/exported-elements.ts +50 -0
- package/src/{adw-button.spec.ts → gtk-button.spec.ts} +6 -6
- package/src/{adw-drop-down.spec.ts → gtk-drop-down.spec.ts} +17 -17
- package/src/{adw-entry.spec.ts → gtk-entry.spec.ts} +8 -8
- package/src/{adw-icon.spec.ts → gtk-image.spec.ts} +21 -21
- package/src/{adw-menu-button.spec.ts → gtk-menu-button.spec.ts} +6 -6
- package/src/{adw-progress-bar.spec.ts → gtk-progress-bar.spec.ts} +12 -12
- package/src/{adw-switch.spec.ts → gtk-switch.spec.ts} +20 -20
- package/src/icon-registry.spec.ts +6 -6
- package/src/icon-registry.ts +6 -6
- package/src/index.ts +64 -63
- package/src/namespace/adw.ts +99 -0
- package/src/namespace/gtk.ts +22 -0
- package/src/preferences-search.ts +1 -1
- package/src/slotted-children.spec.ts +5 -3
- package/src/source-view/adw-source-view.ts +2 -2
- package/src/split-button.spec.ts +5 -5
- package/src/styles.generated.ts +1 -1
- package/src/test.browser.mts +15 -15
- package/lib/types/adw-button.spec.d.ts +0 -1
- package/lib/types/adw-drop-down.spec.d.ts +0 -1
- package/lib/types/adw-entry.spec.d.ts +0 -1
- package/lib/types/adw-icon.spec.d.ts +0 -1
- package/lib/types/adw-menu-button.spec.d.ts +0 -1
- package/lib/types/adw-progress-bar.spec.d.ts +0 -1
- package/lib/types/adw-switch.spec.d.ts +0 -1
- /package/lib/types/{adw-checks.spec.d.ts → checks.spec.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// DOM-level tests for <
|
|
1
|
+
// DOM-level tests for <gtk-check-button> and <adw-radio>, plus the browser side of
|
|
2
2
|
// the `RADIO_GROUP_VECTORS` conformance table.
|
|
3
3
|
//
|
|
4
4
|
// The browser's native radio exclusivity is NOT enough: `<input type="radio" name="g">`
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { describe, expect, it } from '@gjsify/unit';
|
|
15
15
|
import { RADIO_GROUP_VECTORS } from '@gjsify/adwaita-core/conformance';
|
|
16
16
|
|
|
17
|
-
import type {
|
|
17
|
+
import type { GtkCheckButton, AdwRadio } from './elements/checks.js';
|
|
18
18
|
|
|
19
19
|
function host(): HTMLElement {
|
|
20
20
|
const el = document.createElement('div');
|
|
@@ -22,9 +22,9 @@ function host(): HTMLElement {
|
|
|
22
22
|
return el;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function mountCheckbox(): { el:
|
|
25
|
+
function mountCheckbox(): { el: GtkCheckButton; parent: HTMLElement } {
|
|
26
26
|
const parent = host();
|
|
27
|
-
const el = document.createElement('
|
|
27
|
+
const el = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
28
28
|
parent.appendChild(el);
|
|
29
29
|
return { el, parent };
|
|
30
30
|
}
|
|
@@ -51,7 +51,7 @@ function glyph(check: HTMLElement): string {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export const AdwChecksTest = async () => {
|
|
54
|
-
await describe('<
|
|
54
|
+
await describe('<gtk-check-button> state', async () => {
|
|
55
55
|
await it('builds the input + indicator + label markup', () => {
|
|
56
56
|
const { el, parent } = mountCheckbox();
|
|
57
57
|
const { input, indicator, label } = parts(el);
|
|
@@ -69,13 +69,13 @@ export const AdwChecksTest = async () => {
|
|
|
69
69
|
|
|
70
70
|
await it('adopts authored child nodes as the label, and the attribute wins', () => {
|
|
71
71
|
const parent = host();
|
|
72
|
-
const authored = document.createElement('
|
|
72
|
+
const authored = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
73
73
|
authored.textContent = 'Enable';
|
|
74
74
|
parent.appendChild(authored);
|
|
75
75
|
expect(parts(authored).label.textContent).toBe('Enable');
|
|
76
76
|
expect(parts(authored).label.hidden).toBe(false);
|
|
77
77
|
|
|
78
|
-
const labelled = document.createElement('
|
|
78
|
+
const labelled = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
79
79
|
labelled.setAttribute('label', 'From the attribute');
|
|
80
80
|
labelled.textContent = 'ignored';
|
|
81
81
|
parent.appendChild(labelled);
|
|
@@ -133,7 +133,7 @@ export const AdwChecksTest = async () => {
|
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
await describe('<
|
|
136
|
+
await describe('<gtk-check-button> indeterminate', async () => {
|
|
137
137
|
await it('announces as mixed and outranks checked', () => {
|
|
138
138
|
const { el, parent } = mountCheckbox();
|
|
139
139
|
el.checked = true;
|
|
@@ -152,7 +152,7 @@ export const AdwChecksTest = async () => {
|
|
|
152
152
|
// three states proves the cascade, not just that a mask exists.
|
|
153
153
|
const parent = host();
|
|
154
154
|
const make = (attrs: string[]) => {
|
|
155
|
-
const el = document.createElement('
|
|
155
|
+
const el = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
156
156
|
for (const attr of attrs) el.setAttribute(attr, '');
|
|
157
157
|
parent.appendChild(el);
|
|
158
158
|
return el;
|
|
@@ -181,7 +181,7 @@ export const AdwChecksTest = async () => {
|
|
|
181
181
|
await describe('check and radio share one stylesheet', async () => {
|
|
182
182
|
await it('both draw the 14px + 3px indicator, differing only in the radius', () => {
|
|
183
183
|
const parent = host();
|
|
184
|
-
const check = document.createElement('
|
|
184
|
+
const check = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
185
185
|
const radio = document.createElement('adw-radio') as AdwRadio;
|
|
186
186
|
parent.append(check, radio);
|
|
187
187
|
|
|
@@ -219,7 +219,7 @@ export const AdwChecksTest = async () => {
|
|
|
219
219
|
radio.setAttribute('name', 'fill-checked');
|
|
220
220
|
radio.setAttribute('value', 'x');
|
|
221
221
|
radio.setAttribute('checked', '');
|
|
222
|
-
const check = document.createElement('
|
|
222
|
+
const check = document.createElement('gtk-check-button') as GtkCheckButton;
|
|
223
223
|
check.setAttribute('checked', '');
|
|
224
224
|
parent.append(plain, radio, check);
|
|
225
225
|
|
package/src/chrome.spec.ts
CHANGED
|
@@ -153,7 +153,7 @@ const ROOT_ACTION_PREVIEW = `
|
|
|
153
153
|
<adw-window-title slot="center" title="Contacts"></adw-window-title>
|
|
154
154
|
</adw-header-bar>
|
|
155
155
|
<div style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">
|
|
156
|
-
<
|
|
156
|
+
<gtk-button label="Open contact" pill suggested></gtk-button>
|
|
157
157
|
</div>
|
|
158
158
|
</adw-toolbar-view>`;
|
|
159
159
|
|
|
@@ -530,7 +530,7 @@ export const AdwChromeTest = async () => {
|
|
|
530
530
|
const host = mountPreview(ROOT_ACTION_PREVIEW);
|
|
531
531
|
await settle();
|
|
532
532
|
const area = host.querySelector('.adw-toolbar-view-content') as HTMLElement;
|
|
533
|
-
const button = host.querySelector('
|
|
533
|
+
const button = host.querySelector('gtk-button') as HTMLElement;
|
|
534
534
|
|
|
535
535
|
expect(heightOf(area.firstElementChild)).toBe(heightOf(area));
|
|
536
536
|
// A pill button that grew to the pane's height would be the fill applied
|
|
@@ -24,10 +24,14 @@
|
|
|
24
24
|
import { describe, expect, it } from '@gjsify/unit';
|
|
25
25
|
|
|
26
26
|
import * as adwaitaWeb from './index.js';
|
|
27
|
+
// Not a bare `Object.values` walk: since ADR 0034 § Amendment 6 the widget classes are
|
|
28
|
+
// members of the exported `Adw`/`Gtk` objects, so a top-level scan reaches only the
|
|
29
|
+
// web-only stragglers while reading as if it swept the package.
|
|
30
|
+
import { exportedElementClasses } from './exported-elements.js';
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Elements that cannot RENDER a child, however the DOM lets you append one. A container
|
|
30
|
-
* getter returning one of these is an imperative handle (`<
|
|
34
|
+
* getter returning one of these is an imperative handle (`<gtk-entry>.input`, for
|
|
31
35
|
* focus and selection), not an append point, and appending to it measures 0 forever.
|
|
32
36
|
* The HTML void-element set, not a per-widget ledger — a new container still enrols
|
|
33
37
|
* itself; only a new void element in the spec would need a line here.
|
|
@@ -85,9 +89,8 @@ function reveal(el: HTMLElement): void {
|
|
|
85
89
|
function registeredElements(): { tags: string[]; unregistered: string[] } {
|
|
86
90
|
const tags: string[] = [];
|
|
87
91
|
const unregistered: string[] = [];
|
|
88
|
-
for (const exported of
|
|
89
|
-
|
|
90
|
-
const tag = customElements.getName(exported as CustomElementConstructor);
|
|
92
|
+
for (const exported of exportedElementClasses(adwaitaWeb)) {
|
|
93
|
+
const tag = customElements.getName(exported);
|
|
91
94
|
if (tag === null) unregistered.push(exported.name);
|
|
92
95
|
else tags.push(tag);
|
|
93
96
|
}
|
|
@@ -101,7 +104,7 @@ function registeredElements(): { tags: string[]; unregistered: string[] } {
|
|
|
101
104
|
* Each half earns its place. No setter, because a container you append into is not one
|
|
102
105
|
* you replace by assignment — that is what separates `topBar` from `anchor` and
|
|
103
106
|
* `activatableWidget`. Contained, because the handle has to be part of THIS widget's
|
|
104
|
-
* own subtree — `<
|
|
107
|
+
* own subtree — `<gtk-popover>.anchor` defaults to `parentElement` and is not. And a
|
|
105
108
|
* value that is not an element at all (`items`, `groups`, a `null` slot on an empty
|
|
106
109
|
* widget) is nothing to append to.
|
|
107
110
|
*
|
|
@@ -326,9 +329,9 @@ export const AdwConnectLifecycleTest = async () => {
|
|
|
326
329
|
});
|
|
327
330
|
}
|
|
328
331
|
|
|
329
|
-
await it('<
|
|
332
|
+
await it('<gtk-popover> still dismisses on an outside click after a move', async () => {
|
|
330
333
|
const first = visibleHost();
|
|
331
|
-
const popover = document.createElement('
|
|
334
|
+
const popover = document.createElement('gtk-popover');
|
|
332
335
|
first.appendChild(popover);
|
|
333
336
|
(popover as HTMLElement & { popup(): void }).popup();
|
|
334
337
|
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
// Reference: refs/adwaita-web/adwaita-web/scss/_about_dialog.scss (web layout)
|
|
56
56
|
// Copyright (c) 2022-2024 GNOME Foundation Inc. / Purism SPC (libadwaita). LGPLv2.1+.
|
|
57
57
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
58
|
-
// icon nodes are <
|
|
58
|
+
// icon nodes are <gtk-image>; the derivations live in @gjsify/adwaita-core.
|
|
59
59
|
|
|
60
60
|
import {
|
|
61
61
|
ADW_ABOUT_DIALOG_LABELS,
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
stripMnemonic,
|
|
68
68
|
} from '@gjsify/adwaita-core';
|
|
69
69
|
|
|
70
|
-
import {
|
|
70
|
+
import { createGtkImage } from './gtk-image.js';
|
|
71
71
|
import { AdwModalSurface } from './modal-surface.js';
|
|
72
72
|
|
|
73
73
|
/** A template label with its mnemonic marker removed — this renderer has no accelerator layer. */
|
|
@@ -440,7 +440,7 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
440
440
|
// `image-missing` rather than three stray classes; that is also what GTK draws for
|
|
441
441
|
// it on a machine without the app installed.
|
|
442
442
|
if (visibility.appIcon) {
|
|
443
|
-
body.appendChild(
|
|
443
|
+
body.appendChild(createGtkImage(this.applicationIcon, 'adw-about-dialog-icon'));
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
// No fallback: an unset name means no label.
|
|
@@ -518,7 +518,7 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
518
518
|
row.setAttribute('title', title);
|
|
519
519
|
row.setAttribute('activatable', '');
|
|
520
520
|
|
|
521
|
-
const chevron =
|
|
521
|
+
const chevron = createGtkImage('go-next', 'adw-about-dialog-chevron');
|
|
522
522
|
chevron.setAttribute('slot', 'suffix');
|
|
523
523
|
row.appendChild(chevron);
|
|
524
524
|
|
|
@@ -569,7 +569,7 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
569
569
|
row.setAttribute('activatable', '');
|
|
570
570
|
row.classList.add('adw-about-dialog-link-row');
|
|
571
571
|
|
|
572
|
-
const chevron =
|
|
572
|
+
const chevron = createGtkImage('go-next', 'adw-about-dialog-chevron');
|
|
573
573
|
chevron.setAttribute('slot', 'suffix');
|
|
574
574
|
row.appendChild(chevron);
|
|
575
575
|
|
|
@@ -603,7 +603,7 @@ export class AdwAboutDialog extends HTMLElement {
|
|
|
603
603
|
const uri = person.uri ?? '';
|
|
604
604
|
row.setAttribute('activatable', '');
|
|
605
605
|
row.classList.add('adw-about-dialog-link-row');
|
|
606
|
-
const chevron =
|
|
606
|
+
const chevron = createGtkImage('go-next', 'adw-about-dialog-chevron');
|
|
607
607
|
chevron.setAttribute('slot', 'suffix');
|
|
608
608
|
row.appendChild(chevron);
|
|
609
609
|
row.addEventListener('activated', () => this._activateLink(uri));
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Reference: refs/adwaita-web/adwaita-web/scss/_avatar.scss
|
|
8
8
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
9
9
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
10
|
-
// fallback icon node is <
|
|
10
|
+
// fallback icon node is <gtk-image>.
|
|
11
11
|
//
|
|
12
12
|
// The two derivations — initials from the name, and the palette colour the name hashes to
|
|
13
13
|
// — are HEADLESS and live in `@gjsify/adwaita-core` (ADR 0004) as {@link avatarInitials} /
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
|
|
22
22
|
import { avatarColor, avatarFontSize, avatarInitials, avatarMaxFontSize, avatarMode } from '@gjsify/adwaita-core';
|
|
23
23
|
|
|
24
|
-
import { type
|
|
24
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
25
25
|
|
|
26
26
|
export class AdwAvatar extends HTMLElement {
|
|
27
27
|
private _textEl!: HTMLSpanElement;
|
|
28
|
-
private _iconEl!:
|
|
28
|
+
private _iconEl!: GtkImage;
|
|
29
29
|
private _imageEl!: HTMLImageElement;
|
|
30
30
|
private _initialized = false;
|
|
31
31
|
|
|
@@ -40,7 +40,7 @@ export class AdwAvatar extends HTMLElement {
|
|
|
40
40
|
this._textEl = document.createElement('span');
|
|
41
41
|
this._textEl.className = 'adw-avatar-text';
|
|
42
42
|
|
|
43
|
-
this._iconEl =
|
|
43
|
+
this._iconEl = createGtkImage(null, 'adw-avatar-icon');
|
|
44
44
|
|
|
45
45
|
this._imageEl = document.createElement('img');
|
|
46
46
|
this._imageEl.className = 'adw-avatar-custom-image';
|
|
@@ -20,15 +20,15 @@
|
|
|
20
20
|
// (image-text-button · the splitbutton override · buttoncontent)
|
|
21
21
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
22
22
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
23
|
-
// icon node is <
|
|
23
|
+
// icon node is <gtk-image>.
|
|
24
24
|
|
|
25
25
|
import { BUTTON_CONTENT_STYLE_CLASS, buttonContentIconName, buttonContentLabelText } from '@gjsify/adwaita-core';
|
|
26
26
|
|
|
27
|
-
import { type
|
|
27
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* What `gtk_widget_get_ancestor (…, GTK_TYPE_BUTTON)` looks like in the DOM: a native
|
|
31
|
-
* `<button>`, or anything wearing the Adwaita button class — `<
|
|
31
|
+
* `<button>`, or anything wearing the Adwaita button class — `<gtk-button>` renders an
|
|
32
32
|
* inner button with it, and the stories put it on plain ones.
|
|
33
33
|
*/
|
|
34
34
|
const BUTTON_SELECTOR = 'button, .adw-button';
|
|
@@ -38,7 +38,7 @@ const SPLIT_BUTTON_SELECTOR = 'adw-split-button, .adw-split-button';
|
|
|
38
38
|
|
|
39
39
|
export class AdwButtonContent extends HTMLElement {
|
|
40
40
|
private _boxEl!: HTMLDivElement;
|
|
41
|
-
private _iconEl!:
|
|
41
|
+
private _iconEl!: GtkImage;
|
|
42
42
|
private _labelEl!: HTMLSpanElement;
|
|
43
43
|
private _initialized = false;
|
|
44
44
|
/** The node currently carrying `image-text-button`, so unroot can find it. */
|
|
@@ -57,9 +57,9 @@ export class AdwButtonContent extends HTMLElement {
|
|
|
57
57
|
this._boxEl.className = 'adw-button-content-box';
|
|
58
58
|
|
|
59
59
|
// The image node is GTK_ACCESSIBLE_ROLE_PRESENTATION in libadwaita: decorative,
|
|
60
|
-
// with the label carrying the accessible name — what `<
|
|
60
|
+
// with the label carrying the accessible name — what `<gtk-image>`'s own
|
|
61
61
|
// `aria-hidden` already says.
|
|
62
|
-
this._iconEl =
|
|
62
|
+
this._iconEl = createGtkImage(null);
|
|
63
63
|
|
|
64
64
|
this._labelEl = document.createElement('span');
|
|
65
65
|
this._labelEl.className = 'adw-button-content-label';
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
|
|
22
22
|
import { BUTTON_ROW_ACTIVATABLE, ButtonRowState } from '@gjsify/adwaita-core';
|
|
23
23
|
|
|
24
|
-
import { type
|
|
24
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
25
25
|
import { attachRowActivation } from './row-activation.js';
|
|
26
26
|
|
|
27
27
|
export class AdwButtonRow extends HTMLElement {
|
|
28
28
|
private _contentsEl!: HTMLDivElement;
|
|
29
|
-
private _startIconEl!:
|
|
30
|
-
private _endIconEl!:
|
|
29
|
+
private _startIconEl!: GtkImage;
|
|
30
|
+
private _endIconEl!: GtkImage;
|
|
31
31
|
private _titleEl!: HTMLSpanElement;
|
|
32
32
|
/** The headless title + start/end icon state (ADR 0004). */
|
|
33
33
|
private readonly _state = new ButtonRowState();
|
|
@@ -43,12 +43,12 @@ export class AdwButtonRow extends HTMLElement {
|
|
|
43
43
|
this._contentsEl = document.createElement('div');
|
|
44
44
|
this._contentsEl.className = 'adw-button-row-contents';
|
|
45
45
|
|
|
46
|
-
this._startIconEl =
|
|
46
|
+
this._startIconEl = createGtkImage(null, 'start');
|
|
47
47
|
|
|
48
48
|
this._titleEl = document.createElement('span');
|
|
49
49
|
this._titleEl.className = 'adw-button-row-title';
|
|
50
50
|
|
|
51
|
-
this._endIconEl =
|
|
51
|
+
this._endIconEl = createGtkImage(null, 'end');
|
|
52
52
|
|
|
53
53
|
this._contentsEl.append(this._startIconEl, this._titleEl, this._endIconEl);
|
|
54
54
|
this.replaceChildren(this._contentsEl);
|
|
@@ -89,7 +89,7 @@ export class AdwButtonRow extends HTMLElement {
|
|
|
89
89
|
* The `start` / `end` position class is set once at construction — it is
|
|
90
90
|
* where the node sits, not what it draws — so only the name changes here.
|
|
91
91
|
*/
|
|
92
|
-
private _paintIcon(el:
|
|
92
|
+
private _paintIcon(el: GtkImage, iconName: string, visible: boolean) {
|
|
93
93
|
el.iconName = visible ? iconName : null;
|
|
94
94
|
el.hidden = !visible;
|
|
95
95
|
}
|
|
@@ -43,7 +43,7 @@ export class AdwComboRow extends HTMLElement {
|
|
|
43
43
|
const items: string[] = JSON.parse(this.getAttribute('items') || '[]');
|
|
44
44
|
// Seed the headless state BEFORE subscribing, so building the initial DOM below is
|
|
45
45
|
// not driven by a change notification. The string→descriptor mapping is core's, so
|
|
46
|
-
// this row and `<
|
|
46
|
+
// this row and `<gtk-drop-down>` accept one option vocabulary.
|
|
47
47
|
this._state.setOptions(normalizeComboOptions(items));
|
|
48
48
|
this._state.setSelectedIndex(parseInt(this.getAttribute('selected') || '0', 10));
|
|
49
49
|
const selectedIdx = this._state.selectedIndex;
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// Reference: refs/libadwaita/src/stylesheet/widgets/_entries.scss
|
|
28
28
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
29
29
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
30
|
-
// edit icon node is <
|
|
30
|
+
// edit icon node is <gtk-image>.
|
|
31
31
|
|
|
32
32
|
import {
|
|
33
33
|
ENTRY_ROW_APPLY_ICON_NAME,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from '@gjsify/adwaita-core';
|
|
39
39
|
|
|
40
40
|
import { bindSlottedChildren, type AdwSlottedChildren } from '../slotted-children.js';
|
|
41
|
-
import { type
|
|
41
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Show/hide a rendered part. `hidden` carries the semantics and is what the conformance
|
|
@@ -66,7 +66,7 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
66
66
|
protected _title!: HTMLSpanElement;
|
|
67
67
|
/** The `editable-area` gizmo: both titles plus the input. */
|
|
68
68
|
protected _area!: HTMLDivElement;
|
|
69
|
-
protected _editIcon!:
|
|
69
|
+
protected _editIcon!: GtkImage;
|
|
70
70
|
protected _indicator!: HTMLSpanElement;
|
|
71
71
|
protected _applyButton!: HTMLButtonElement;
|
|
72
72
|
protected _prefixes!: HTMLDivElement;
|
|
@@ -326,11 +326,11 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
326
326
|
// The libadwaita name travels in `data-icon-name`; the drawn glyph is
|
|
327
327
|
// the curated @gjsify/adwaita-icons spelling of the same symbolic, which
|
|
328
328
|
// is a different string (`adw-entry-edit-symbolic` vs `document-edit`).
|
|
329
|
-
this._editIcon =
|
|
329
|
+
this._editIcon = createGtkImage('document-edit', 'adw-row-edit', `${prefix}-edit`);
|
|
330
330
|
this._editIcon.dataset.iconName = ENTRY_ROW_EDIT_ICON_NAME;
|
|
331
331
|
|
|
332
332
|
// Author-supplied light-DOM children are KEPT and stay LIVE: `replaceChildren` used
|
|
333
|
-
// to discard them silently, so `<adw-entry-row><
|
|
333
|
+
// to discard them silently, so `<adw-entry-row><gtk-button>Go</gtk-button>` rendered
|
|
334
334
|
// without its button, and the snapshot that fixed that was still a one-shot read — a
|
|
335
335
|
// suffix appended after connect sat outside the affordance box. ELEMENTS only, on
|
|
336
336
|
// both paths: GtkBuildable also only ever adopts widgets, and keeping stray
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// Copyright (c) GNOME contributors (libadwaita). LGPLv2.1+.
|
|
18
18
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
19
19
|
// disclosure state machine composed from @gjsify/adwaita-core, the enable
|
|
20
|
-
// switch from <
|
|
20
|
+
// switch from <gtk-switch> and the chevron from <gtk-image>.
|
|
21
21
|
|
|
22
22
|
import { ExpanderState, deriveRowLabels } from '@gjsify/adwaita-core';
|
|
23
23
|
|
|
@@ -25,22 +25,22 @@ import { bindEmptySections } from '../empty-sections.js';
|
|
|
25
25
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
26
26
|
|
|
27
27
|
// SIDE-EFFECT import, deliberately separate from the type import below: it guarantees
|
|
28
|
-
// `
|
|
28
|
+
// `gtk-switch` is defined before this module's `customElements.define` can upgrade a
|
|
29
29
|
// server-rendered `<adw-expander-row>` and build one. A combined
|
|
30
|
-
// `import {
|
|
30
|
+
// `import { GtkSwitch }` would NOT do it — the binding is only used in type position,
|
|
31
31
|
// and this package compiles without `verbatimModuleSyntax`, so TypeScript would elide
|
|
32
32
|
// the statement and take the registration with it.
|
|
33
|
-
import './
|
|
34
|
-
import type {
|
|
35
|
-
import { type
|
|
33
|
+
import './gtk-switch.js';
|
|
34
|
+
import type { GtkSwitch } from './gtk-switch.js';
|
|
35
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
36
36
|
import { attachRowActivation } from './row-activation.js';
|
|
37
37
|
|
|
38
38
|
export class AdwExpanderRow extends HTMLElement {
|
|
39
39
|
private _headerEl!: HTMLDivElement;
|
|
40
40
|
private _titleEl!: HTMLSpanElement;
|
|
41
41
|
private _subtitleEl!: HTMLSpanElement;
|
|
42
|
-
private _enableSwitch!:
|
|
43
|
-
private _chevronEl!:
|
|
42
|
+
private _enableSwitch!: GtkSwitch;
|
|
43
|
+
private _chevronEl!: GtkImage;
|
|
44
44
|
private _contentEl!: HTMLDivElement;
|
|
45
45
|
private _prefixEl!: HTMLDivElement;
|
|
46
46
|
private _suffixEl!: HTMLDivElement;
|
|
@@ -118,11 +118,11 @@ export class AdwExpanderRow extends HTMLElement {
|
|
|
118
118
|
textEl.append(this._titleEl, this._subtitleEl);
|
|
119
119
|
|
|
120
120
|
// Clicking the enable switch does NOT toggle the disclosure.
|
|
121
|
-
this._enableSwitch = document.createElement('
|
|
121
|
+
this._enableSwitch = document.createElement('gtk-switch') as GtkSwitch;
|
|
122
122
|
this._enableSwitch.classList.add('adw-expander-row-enable-switch');
|
|
123
123
|
this._enableSwitch.active = this.enableExpansion;
|
|
124
124
|
|
|
125
|
-
this._chevronEl =
|
|
125
|
+
this._chevronEl = createGtkImage('go-down', 'adw-expander-row-chevron');
|
|
126
126
|
|
|
127
127
|
this._prefixEl = document.createElement('div');
|
|
128
128
|
this._prefixEl.className = 'adw-expander-row-prefix';
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
// <adw-header-bar> — Adwaita header bar with centered title and start/end button slots.
|
|
2
2
|
//
|
|
3
|
-
// The derived centre is an `<adw-window-title
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// The derived centre is an `<adw-window-title>`. That is a DIVERGENCE, and the comment
|
|
4
|
+
// here used to claim the opposite — that `Adw.HeaderBar` puts one there. Measured
|
|
5
|
+
// against the source: `construct_title_label` (adw-header-bar.c:512) builds a plain
|
|
6
|
+
// `gtk_label_new (NULL)` with the `title` class, `single-line-mode` and
|
|
7
|
+
// `ellipsize=END`, and `Adw.HeaderBar` has NO `title` property at all — `update_title`
|
|
8
|
+
// (:475) resolves one from the navigation page, then the dialog, then the root window,
|
|
9
|
+
// then `g_get_application_name`, then `g_get_prgname`. An app that wants a subtitle
|
|
10
|
+
// there sets an `AdwWindowTitle` as its title-widget.
|
|
11
|
+
//
|
|
12
|
+
// The divergence is kept: a declarative surface wants `title=` / `subtitle=` attributes
|
|
13
|
+
// rather than a widget handoff, and both renderers already use them. It is recorded as
|
|
14
|
+
// `HeaderBarRenderState.derivedSubtitle` in `@gjsify/adwaita-core`, so it is a named
|
|
15
|
+
// difference instead of a mistaken claim of fidelity.
|
|
16
|
+
//
|
|
17
|
+
// It used to be a bare span with
|
|
6
18
|
// `textContent = title ?? ''`, and that span carried none of the three rules the
|
|
7
19
|
// window title already held in `@gjsify/adwaita-core`: an EMPTY title still
|
|
8
20
|
// reserved a blank line, re-setting the same value repainted, and there was no
|
|
@@ -29,8 +41,10 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
29
41
|
private _endEl: HTMLDivElement | null = null;
|
|
30
42
|
/**
|
|
31
43
|
* The derived `<adw-window-title>`, or `null` when a `slot="center"`
|
|
32
|
-
* title-widget took the centre. `Adw.HeaderBar` has the same either/or
|
|
33
|
-
*
|
|
44
|
+
* title-widget took the centre. `Adw.HeaderBar` has the same either/or —
|
|
45
|
+
* `adw_header_bar_set_title_widget` empties the centre bin before installing
|
|
46
|
+
* (adw-header-bar.c:1201) — over a derived `GtkLabel`, not an `AdwWindowTitle`;
|
|
47
|
+
* see the divergence at the top of this file.
|
|
34
48
|
*/
|
|
35
49
|
private _titleEl: HTMLElement | null = null;
|
|
36
50
|
|
|
@@ -86,8 +100,9 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
86
100
|
).install(this._startEl, this._centerEl, this._endEl);
|
|
87
101
|
|
|
88
102
|
// Derived only when the centre is still free — the same either/or as
|
|
89
|
-
// `Adw.HeaderBar`, which
|
|
90
|
-
//
|
|
103
|
+
// `Adw.HeaderBar`, which runs `construct_title_label` exactly while no
|
|
104
|
+
// title-widget holds the centre (adw-header-bar.c:1211). What it builds there is
|
|
105
|
+
// a `GtkLabel`; this is the documented `<adw-window-title>` divergence.
|
|
91
106
|
if (this._centerEl.childElementCount === 0) {
|
|
92
107
|
this._titleEl = document.createElement('adw-window-title');
|
|
93
108
|
this._titleEl.className = 'adw-header-bar-title';
|
|
@@ -99,18 +114,24 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
99
114
|
/**
|
|
100
115
|
* `title` used to be read ONCE, in `connectedCallback`, so every later write
|
|
101
116
|
* was a silent no-op — a header bar whose title tracked the open document
|
|
102
|
-
* kept whatever it was created with. `Adw.HeaderBar`
|
|
103
|
-
*
|
|
117
|
+
* kept whatever it was created with. `Adw.HeaderBar` never reads its title once
|
|
118
|
+
* either: it has no `title` property at all, and re-runs `update_title`
|
|
119
|
+
* (adw-header-bar.c:475) on every ancestor change that could move the answer.
|
|
104
120
|
*/
|
|
105
121
|
attributeChangedCallback() {
|
|
106
122
|
if (this._initialized) this._renderTitle();
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
/**
|
|
110
|
-
* Give the centre up to a title-widget. `adw_header_bar_set_title_widget`
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* produce.
|
|
126
|
+
* Give the centre up to a title-widget. `adw_header_bar_set_title_widget` empties the
|
|
127
|
+
* centre bin and drops its derived label (adw-header-bar.c:1201, :1209) rather than
|
|
128
|
+
* stacking the two, so the late case has to remove ours too — a bar showing both would
|
|
129
|
+
* be a shape neither GTK nor the declared markup can produce.
|
|
130
|
+
*
|
|
131
|
+
* NOT SYMMETRIC HERE, AND KNOWN: C rebuilds the label the moment the title-widget goes
|
|
132
|
+
* away (:1211); nothing in this element brings the derived centre back, so a bar that
|
|
133
|
+
* gave it up has given it up for good. `HeaderBarState` in `@gjsify/adwaita-core` holds
|
|
134
|
+
* the rebuild, and this element adopting it is the rewiring tracked in #1343.
|
|
114
135
|
*/
|
|
115
136
|
private _dropDerivedTitle() {
|
|
116
137
|
this._titleEl?.remove();
|
|
@@ -100,8 +100,20 @@ export class AdwNavigationPage extends HTMLElement {
|
|
|
100
100
|
// back-button derivation read the CORE's copy — so a runtime change has to
|
|
101
101
|
// be pushed into it. Without this the back button only ever reflected the
|
|
102
102
|
// `can-pop` value it had at the last stack mutation.
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
//
|
|
104
|
+
// `instanceof` rather than a cast plus `?.`: the two failures the `?.`
|
|
105
|
+
// conflated are different. A MISSING ancestor is one; an ancestor that IS
|
|
106
|
+
// there but is still an ordinary HTMLElement, because its own definition has
|
|
107
|
+
// not upgraded it yet, is the other, and the cast asserted it away. Measured
|
|
108
|
+
// on `dist/test.browser.mjs` against declared markup parsed before the module
|
|
109
|
+
// loaded: `syncPageProperty is not a function`, once per observed attribute
|
|
110
|
+
// per declared page. Dropping the notification for an un-upgraded view loses
|
|
111
|
+
// nothing — such a view has not registered this page, `syncPageProperty`
|
|
112
|
+
// already returns on `!isRegistered`, and `connectedCallback` reads the
|
|
113
|
+
// properties back out of the element through `readPageProps`.
|
|
114
|
+
const view = this.closest('adw-navigation-view');
|
|
115
|
+
if (!(view instanceof AdwNavigationView)) return;
|
|
116
|
+
view.syncPageProperty(this, name, previous);
|
|
105
117
|
}
|
|
106
118
|
|
|
107
119
|
revertAttribute(name: string, value: string | null): void {
|
|
@@ -445,7 +457,7 @@ export class AdwNavigationView extends HTMLElement {
|
|
|
445
457
|
const start = (headerBar as { startSection?: HTMLElement | null }).startSection ?? null;
|
|
446
458
|
if (!start) return;
|
|
447
459
|
|
|
448
|
-
const back = document.createElement('
|
|
460
|
+
const back = document.createElement('gtk-button');
|
|
449
461
|
back.classList.add('adw-navigation-back-button');
|
|
450
462
|
back.setAttribute('icon', 'go-previous');
|
|
451
463
|
back.setAttribute('flat', '');
|
|
@@ -464,5 +476,13 @@ export class AdwNavigationView extends HTMLElement {
|
|
|
464
476
|
}
|
|
465
477
|
}
|
|
466
478
|
|
|
467
|
-
|
|
479
|
+
// The VIEW first, and the order carries weight: `define` upgrades every matching
|
|
480
|
+
// element already in the document, immediately, so these two calls are a sequence and
|
|
481
|
+
// not a pair. Registering the page first upgraded every declared
|
|
482
|
+
// `<adw-navigation-page>` while its `<adw-navigation-view>` parent was still an
|
|
483
|
+
// ordinary HTMLElement, and `AdwNavigationPage.attributeChangedCallback` reaches for
|
|
484
|
+
// that parent. Parent before child keeps the window shut; the `instanceof` guard in
|
|
485
|
+
// the callback is what holds when something outside this file reopens it.
|
|
486
|
+
// `scripts/check-adwaita-upgrade-order.mjs` holds the order itself.
|
|
468
487
|
customElements.define('adw-navigation-view', AdwNavigationView);
|
|
488
|
+
customElements.define('adw-navigation-page', AdwNavigationPage);
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { PasswordEntryRowState, type PasswordEntryRowRenderState } from '@gjsify/adwaita-core';
|
|
24
24
|
|
|
25
|
-
import { type
|
|
25
|
+
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
26
26
|
|
|
27
27
|
import { AdwEntryRow } from './adw-entry-row.js';
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ export class AdwPasswordEntryRow extends AdwEntryRow {
|
|
|
30
30
|
/** The headless peek + caps-lock derivation, composing the parent row's state. */
|
|
31
31
|
private readonly _password = new PasswordEntryRowState(this._state);
|
|
32
32
|
private _toggle!: HTMLButtonElement;
|
|
33
|
-
private _toggleIcon!:
|
|
33
|
+
private _toggleIcon!: GtkImage;
|
|
34
34
|
|
|
35
35
|
static get observedAttributes(): string[] {
|
|
36
36
|
return [...AdwEntryRow.observedAttributes, 'revealed'];
|
|
@@ -73,7 +73,7 @@ export class AdwPasswordEntryRow extends AdwEntryRow {
|
|
|
73
73
|
this._toggle = document.createElement('button');
|
|
74
74
|
this._toggle.type = 'button';
|
|
75
75
|
this._toggle.className = `adw-button flat circular icon-only ${this._classPrefix}-toggle`;
|
|
76
|
-
this._toggleIcon =
|
|
76
|
+
this._toggleIcon = createGtkImage(null);
|
|
77
77
|
this._toggle.append(this._toggleIcon);
|
|
78
78
|
this._toggle.addEventListener('click', () => this._password.togglePeek());
|
|
79
79
|
// Installed through add_suffix as C does, so it is the FIRST suffix and a
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
// Reference: refs/libadwaita/src/stylesheet/widgets/_sidebars.scss (.navigation-sidebar, sidebar)
|
|
44
44
|
// Copyright (c) 2025 GNOME Foundation Inc. (libadwaita). LGPLv2.1+.
|
|
45
45
|
// Modifications: Implemented as a Web Component for @gjsify/adwaita-web; the
|
|
46
|
-
// icon nodes are <
|
|
46
|
+
// icon nodes are <gtk-image>.
|
|
47
47
|
|
|
48
48
|
import {
|
|
49
49
|
ADW_SIDEBAR_NO_SELECTION,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
type SidebarSelectionChange,
|
|
57
57
|
} from '@gjsify/adwaita-core';
|
|
58
58
|
|
|
59
|
-
import {
|
|
59
|
+
import { createGtkImage } from './gtk-image.js';
|
|
60
60
|
import { attachRovingFocus } from './roving-focus.js';
|
|
61
61
|
|
|
62
62
|
// The sidebar consumes its declared children and drops them from the tree, so a later
|
|
@@ -348,7 +348,7 @@ export class AdwSidebar extends HTMLElement {
|
|
|
348
348
|
row.hidden = item.visible === false;
|
|
349
349
|
row.disabled = item.enabled === false;
|
|
350
350
|
|
|
351
|
-
const iconEl =
|
|
351
|
+
const iconEl = createGtkImage(item.iconName ?? null, 'adw-sidebar-item-icon');
|
|
352
352
|
iconEl.hidden = !flat.iconVisible;
|
|
353
353
|
row.appendChild(iconEl);
|
|
354
354
|
|
|
@@ -371,7 +371,7 @@ export class AdwSidebar extends HTMLElement {
|
|
|
371
371
|
|
|
372
372
|
// Page mode adds a trailing chevron on every row, the way the boxed-list
|
|
373
373
|
// AdwActionRow carries a `go-next-symbolic` arrow.
|
|
374
|
-
row.appendChild(
|
|
374
|
+
row.appendChild(createGtkImage('go-next', 'adw-sidebar-item-arrow'));
|
|
375
375
|
|
|
376
376
|
row.addEventListener('click', () => this._activate(flat.index));
|
|
377
377
|
|