@gjsify/adwaita-web 0.55.0 → 0.57.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 -0
- package/dist/adwaita-web.css +137 -29
- package/dist/adwaita-web.css.map +1 -1
- package/lib/types/adw-status-page.spec.d.ts +1 -0
- package/lib/types/application.d.ts +24 -0
- package/lib/types/application.spec.d.ts +1 -0
- package/lib/types/attributes.d.ts +19 -0
- package/lib/types/elements/adw-action-row.d.ts +4 -0
- package/lib/types/elements/adw-application-window.d.ts +2 -0
- package/lib/types/elements/adw-combo-row.d.ts +4 -0
- package/lib/types/elements/adw-entry-row.d.ts +6 -0
- package/lib/types/elements/adw-expander-row.d.ts +2 -0
- package/lib/types/elements/adw-header-bar.d.ts +6 -0
- package/lib/types/elements/adw-overlay-split-view.d.ts +13 -0
- package/lib/types/elements/adw-sidebar.d.ts +3 -2
- package/lib/types/elements/adw-spin-row.d.ts +6 -0
- package/lib/types/elements/adw-switch-row.d.ts +4 -0
- package/lib/types/elements/adw-toggle-group.d.ts +17 -0
- package/lib/types/elements/adw-view-stack.d.ts +3 -0
- package/lib/types/elements/checks.d.ts +6 -0
- package/lib/types/elements/gtk-application-window.d.ts +2 -0
- package/lib/types/elements/gtk-drop-down.d.ts +3 -0
- package/lib/types/elements/gtk-entry.d.ts +10 -0
- package/lib/types/elements/gtk-menu-button.d.ts +2 -0
- package/lib/types/elements/gtk-scrolled-window.d.ts +26 -2
- package/lib/types/elements/gtk-stack.d.ts +3 -0
- package/lib/types/elements/gtk-switch.d.ts +3 -0
- package/lib/types/elements/gtk-window.d.ts +8 -2
- package/lib/types/glib.spec.d.ts +1 -0
- package/lib/types/gobject-door.d.ts +4 -0
- package/lib/types/gobject-door.spec.d.ts +1 -0
- package/lib/types/gobject-elements.d.ts +17 -0
- package/lib/types/gtksource/gtk-source-view.d.ts +77 -0
- package/lib/types/gtksource/gtk-source-view.spec.d.ts +2 -0
- package/lib/types/gtksource/web-editor-driver.d.ts +44 -0
- package/lib/types/index.d.ts +4 -1
- package/lib/types/menu-actions.spec.d.ts +1 -0
- package/lib/types/namespace/adw.d.ts +1 -0
- package/lib/types/namespace/gio.d.ts +2 -0
- package/lib/types/namespace/glib.d.ts +10 -0
- package/lib/types/namespace/gobject.d.ts +27 -0
- package/lib/types/namespace/gtk-enums.d.ts +22 -0
- package/lib/types/namespace/gtk.d.ts +2 -0
- package/lib/types/namespace/gtksource.d.ts +2 -0
- package/lib/types/row-line-clamp.d.ts +20 -0
- package/lib/types/row-tooltip.d.ts +8 -0
- package/lib/types/row-tooltip.spec.d.ts +1 -0
- package/lib/types/shared-tree-builder.d.ts +69 -20
- package/lib/types/shared-tree-mount.spec.d.ts +1 -0
- package/lib/types/styles.generated.d.ts +1 -1
- package/lib/types/widget-size.spec.d.ts +1 -0
- package/package.json +11 -9
- package/scss/_action_row.scss +39 -15
- package/scss/_button_row.scss +5 -0
- package/scss/_expander_row.scss +36 -3
- package/scss/_headerbar.scss +2 -1
- package/scss/_preferences_row.scss +9 -0
- package/scss/_reset.scss +1 -1
- package/scss/_row.scss +16 -0
- package/scss/_status_page.scss +1 -1
- package/scss/_toggle_group.scss +28 -0
- package/scss/_widget.scss +14 -3
- package/scss/_window.scss +13 -1
- package/src/adw-action-rows.spec.ts +255 -0
- package/src/adw-header-bar.spec.ts +18 -0
- package/src/adw-status-page.spec.ts +124 -0
- package/src/application.spec.ts +75 -0
- package/src/application.ts +92 -0
- package/src/attributes.ts +52 -0
- package/src/capabilities.mjs +3 -0
- package/src/construct-vectors.spec.ts +156 -1
- package/src/elements/adw-action-row.ts +31 -2
- package/src/elements/adw-alert-dialog.ts +4 -1
- package/src/elements/adw-application-window.ts +5 -0
- package/src/elements/adw-button-row.ts +7 -1
- package/src/elements/adw-combo-row.ts +26 -1
- package/src/elements/adw-entry-row.ts +22 -12
- package/src/elements/adw-expander-row.ts +34 -1
- package/src/elements/adw-header-bar.ts +18 -4
- package/src/elements/adw-overlay-split-view.ts +29 -6
- package/src/elements/adw-preferences-row.ts +5 -2
- package/src/elements/adw-sidebar.ts +33 -5
- package/src/elements/adw-spin-row.ts +37 -2
- package/src/elements/adw-split-button.ts +5 -1
- package/src/elements/adw-status-page.ts +10 -2
- package/src/elements/adw-switch-row.ts +25 -1
- package/src/elements/adw-toggle-group.ts +119 -10
- package/src/elements/adw-view-stack.ts +14 -0
- package/src/elements/adw-window.ts +9 -4
- package/src/elements/checks.ts +25 -1
- package/src/elements/gtk-application-window.ts +5 -0
- package/src/elements/gtk-drop-down.ts +16 -0
- package/src/elements/gtk-entry.ts +45 -7
- package/src/elements/gtk-menu-button.ts +12 -1
- package/src/elements/gtk-popover-menu.ts +7 -2
- package/src/elements/gtk-scrolled-window.ts +76 -7
- package/src/elements/gtk-stack.ts +8 -0
- package/src/elements/gtk-switch.ts +8 -0
- package/src/elements/gtk-window.ts +9 -3
- package/src/glib.spec.ts +34 -0
- package/src/gobject-door.spec.ts +119 -0
- package/src/gobject-door.ts +137 -0
- package/src/gobject-elements.ts +172 -0
- package/src/gtk-window.spec.ts +12 -0
- package/src/gtksource/gtk-source-view.spec.ts +69 -0
- package/src/gtksource/gtk-source-view.ts +379 -0
- package/src/gtksource/web-editor-driver.ts +260 -0
- package/src/index.ts +11 -1
- package/src/keyboard-operable.spec.ts +47 -11
- package/src/menu-actions.spec.ts +47 -0
- package/src/namespace/adw.ts +1 -0
- package/src/namespace/gio.ts +2 -0
- package/src/namespace/glib.ts +22 -0
- package/src/namespace/gobject.ts +37 -0
- package/src/namespace/gtk-enums.ts +15 -0
- package/src/namespace/gtk.ts +2 -0
- package/src/namespace/gtksource.ts +9 -0
- package/src/row-line-clamp.ts +74 -0
- package/src/row-tooltip.spec.ts +313 -0
- package/src/row-tooltip.ts +52 -0
- package/src/shared-tree-builder.ts +230 -42
- package/src/shared-tree-mount.spec.ts +130 -0
- package/src/shared-trees.spec.ts +15 -0
- package/src/split-button.spec.ts +2 -0
- package/src/styles.generated.ts +1 -1
- package/src/test.browser.mts +18 -0
- package/src/widget-size.spec.ts +117 -0
|
@@ -41,8 +41,11 @@ import {
|
|
|
41
41
|
} from '@gjsify/adwaita-core';
|
|
42
42
|
|
|
43
43
|
import { AdwWindow } from './adw-window.js';
|
|
44
|
+
import { defineWindowApplication } from '../application.js';
|
|
44
45
|
|
|
45
46
|
export class AdwApplicationWindow extends AdwWindow {
|
|
47
|
+
/** `Gtk.Window:application`: setting it is `add_window` (ADR 0098), set by `defineWindowApplication`. */
|
|
48
|
+
declare application: object | null;
|
|
46
49
|
private _menubarEl: HTMLDivElement | null = null;
|
|
47
50
|
private _model: AdwMenuModel = [];
|
|
48
51
|
|
|
@@ -152,3 +155,5 @@ export class AdwApplicationWindow extends AdwWindow {
|
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
customElements.define('adw-application-window', AdwApplicationWindow);
|
|
158
|
+
|
|
159
|
+
defineWindowApplication(AdwApplicationWindow.prototype);
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
// The label/icon visibility rules are HEADLESS and live in `@gjsify/adwaita-core`
|
|
8
8
|
// (ADR 0004) as {@link ButtonRowState}; this element keeps only the DOM render half.
|
|
9
9
|
//
|
|
10
|
+
// Attributes: title, start-icon-name, end-icon-name, tooltip-text
|
|
11
|
+
// (`Gtk.Widget:tooltip-text`).
|
|
12
|
+
//
|
|
10
13
|
// THERE IS NO `activatable` OPT-OUT, and inventing one would be wrong twice over: the
|
|
11
14
|
// upstream template hardcodes `activatable=True` and the class docs say "AdwButtonRow is
|
|
12
15
|
// always activatable", while `<adw-action-row>` in this same package reads `activatable`
|
|
@@ -21,6 +24,7 @@
|
|
|
21
24
|
|
|
22
25
|
import { BUTTON_ROW_ACTIVATABLE, ButtonRowState } from '@gjsify/adwaita-core';
|
|
23
26
|
|
|
27
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
24
28
|
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
25
29
|
import { attachRowActivation } from './row-activation.js';
|
|
26
30
|
|
|
@@ -34,7 +38,7 @@ export class AdwButtonRow extends HTMLElement {
|
|
|
34
38
|
private _initialized = false;
|
|
35
39
|
|
|
36
40
|
static get observedAttributes() {
|
|
37
|
-
return ['title', 'start-icon-name', 'end-icon-name'];
|
|
41
|
+
return ['title', 'start-icon-name', 'end-icon-name', 'tooltip-text'];
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
connectedCallback() {
|
|
@@ -81,6 +85,8 @@ export class AdwButtonRow extends HTMLElement {
|
|
|
81
85
|
|
|
82
86
|
// Unconditional: an AdwButtonRow has no way to not be activatable.
|
|
83
87
|
this.classList.toggle('activatable', BUTTON_ROW_ACTIVATABLE);
|
|
88
|
+
// The contents box is the whole row here, so it carries the tooltip for all of it.
|
|
89
|
+
applyRowTooltip(this, [this._contentsEl]);
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
/**
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
// title / subtitle — the text column.
|
|
30
30
|
// model — JSON array: `["a","b"]` or `[{"value":"a","label":"A"}]`.
|
|
31
31
|
// selected — the selected index (number).
|
|
32
|
+
// tooltip-text — `Gtk.Widget:tooltip-text` (`src/row-tooltip.ts`).
|
|
33
|
+
// title-lines — clamp title to N lines (0 = unlimited, default)
|
|
34
|
+
// subtitle-lines — clamp subtitle to N lines (0 = unlimited, default)
|
|
32
35
|
// Properties — the `<gtk-drop-down>` set minus `enableSearch` and `active`, which are that
|
|
33
36
|
// element's own popover chrome and have no counterpart on a row that opens a native
|
|
34
37
|
// <select>:
|
|
@@ -58,12 +61,16 @@
|
|
|
58
61
|
import { ComboState, deriveRowLabels, normalizeComboOptions, parseListModel } from '@gjsify/adwaita-core';
|
|
59
62
|
import type { AdwComboOption, AdwListItemsChanged, AdwListModelInput } from '@gjsify/adwaita-core';
|
|
60
63
|
|
|
64
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
61
65
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
62
66
|
import { stringListSlot } from '../string-list-slot.js';
|
|
67
|
+
import { applyRowLineClamp, parseRowLinesAttribute } from '../row-line-clamp.js';
|
|
63
68
|
|
|
64
69
|
export class AdwComboRow extends HTMLElement {
|
|
65
70
|
private _select!: HTMLSelectElement;
|
|
66
71
|
private _valueEl!: HTMLSpanElement;
|
|
72
|
+
/** The label column — kept for `tooltip-text`, which the browser reads off a PART. */
|
|
73
|
+
private _textEl!: HTMLDivElement;
|
|
67
74
|
private _titleEl!: HTMLSpanElement;
|
|
68
75
|
private _subtitleEl!: HTMLSpanElement;
|
|
69
76
|
/** The headless options list + selectedIndex↔selectedValue state machine (ADR 0004). */
|
|
@@ -71,7 +78,7 @@ export class AdwComboRow extends HTMLElement {
|
|
|
71
78
|
private _initialized = false;
|
|
72
79
|
|
|
73
80
|
static get observedAttributes() {
|
|
74
|
-
return ['title', 'subtitle', 'model', 'selected'];
|
|
81
|
+
return ['title', 'subtitle', 'model', 'selected', 'tooltip-text', 'title-lines', 'subtitle-lines'];
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/** The list model (`Adw.ComboRow:model`). Setting it splices the <select> and clamps the selection. */
|
|
@@ -141,6 +148,7 @@ export class AdwComboRow extends HTMLElement {
|
|
|
141
148
|
// survive being attached, and an absent attribute must not blank it.
|
|
142
149
|
const text = document.createElement('div');
|
|
143
150
|
text.className = 'adw-row-text';
|
|
151
|
+
this._textEl = text;
|
|
144
152
|
this._titleEl = document.createElement('span');
|
|
145
153
|
this._titleEl.className = 'adw-row-title';
|
|
146
154
|
this._subtitleEl = document.createElement('span');
|
|
@@ -283,6 +291,23 @@ export class AdwComboRow extends HTMLElement {
|
|
|
283
291
|
this._titleEl.hidden = !labels.titleVisible;
|
|
284
292
|
this._subtitleEl.textContent = labels.subtitle;
|
|
285
293
|
this._subtitleEl.hidden = !labels.subtitleVisible;
|
|
294
|
+
// The <select> is stretched over the whole row (`position: absolute; inset: 0`,
|
|
295
|
+
// `_combo_row.scss`), so it is what the pointer actually lands on — the label column
|
|
296
|
+
// has `pointer-events: none`. A tooltip on the label parts alone would therefore
|
|
297
|
+
// never be reached over the title half of the row.
|
|
298
|
+
applyRowTooltip(this, [this._textEl, this._valueEl, this._select]);
|
|
299
|
+
this._applyLineClamping();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Apply CSS line-clamping based on title-lines/subtitle-lines attributes. */
|
|
303
|
+
private _applyLineClamping(): void {
|
|
304
|
+
applyRowLineClamp({
|
|
305
|
+
titleEl: this._titleEl,
|
|
306
|
+
subtitleEl: this._subtitleEl,
|
|
307
|
+
textContainerEl: this._titleEl.parentElement!,
|
|
308
|
+
getTitleLines: () => parseRowLinesAttribute(this.getAttribute('title-lines')),
|
|
309
|
+
getSubtitleLines: () => parseRowLinesAttribute(this.getAttribute('subtitle-lines')),
|
|
310
|
+
});
|
|
286
311
|
}
|
|
287
312
|
}
|
|
288
313
|
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// held to one table (`@gjsify/adwaita-core/conformance`).
|
|
11
11
|
//
|
|
12
12
|
// Attributes: title, text, editable, max-length, show-apply-button,
|
|
13
|
-
// activates-default. `text-length` is
|
|
14
|
-
// `Adw.EntryRow:text-length`).
|
|
13
|
+
// activates-default, tooltip-text (`Gtk.Widget:tooltip-text`). `text-length` is
|
|
14
|
+
// REFLECTED (read-only, mirrors `Adw.EntryRow:text-length`).
|
|
15
15
|
// Properties: text, editable, maxLength, textLength, showApplyButton,
|
|
16
16
|
// activatesDefault, editing.
|
|
17
17
|
// Events:
|
|
@@ -37,6 +37,8 @@ import {
|
|
|
37
37
|
type EntryRowRenderState,
|
|
38
38
|
} from '@gjsify/adwaita-core';
|
|
39
39
|
|
|
40
|
+
import { booleanAttribute } from '../attributes.js';
|
|
41
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
40
42
|
import { bindSlottedChildren, type AdwSlottedChildren } from '../slotted-children.js';
|
|
41
43
|
import { type GtkImage, createGtkImage } from './gtk-image.js';
|
|
42
44
|
|
|
@@ -51,11 +53,6 @@ function setPartVisible(part: HTMLElement, visible: boolean): void {
|
|
|
51
53
|
part.style.display = visible ? '' : 'none';
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
/** Read a boolean attribute the HTML way, with an explicit `="false"` opt-out. */
|
|
55
|
-
function boolAttribute(value: string | null): boolean {
|
|
56
|
-
return value !== null && value !== 'false';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
56
|
export class AdwEntryRow extends HTMLElement {
|
|
60
57
|
/** The headless `update_empty` derivation + apply latch (ADR 0004). */
|
|
61
58
|
protected readonly _state = new EntryRowState();
|
|
@@ -81,7 +78,7 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
81
78
|
private _lastLength = 0;
|
|
82
79
|
|
|
83
80
|
static get observedAttributes(): string[] {
|
|
84
|
-
return ['title', 'text', 'editable', 'max-length', 'show-apply-button', 'activates-default'];
|
|
81
|
+
return ['title', 'text', 'editable', 'max-length', 'show-apply-button', 'activates-default', 'tooltip-text'];
|
|
85
82
|
}
|
|
86
83
|
|
|
87
84
|
/**
|
|
@@ -158,8 +155,8 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
158
155
|
// before the element was connected survives.
|
|
159
156
|
this._state.setMaxLength(Number.parseInt(this.getAttribute('max-length') ?? '', 10));
|
|
160
157
|
this._state.setEditable(this.getAttribute('editable') !== 'false');
|
|
161
|
-
this._state.setShowApplyButton(
|
|
162
|
-
this._state.setActivatesDefault(
|
|
158
|
+
this._state.setShowApplyButton(booleanAttribute(this.getAttribute('show-apply-button'), false));
|
|
159
|
+
this._state.setActivatesDefault(booleanAttribute(this.getAttribute('activates-default'), false));
|
|
163
160
|
if (this.hasAttribute('text')) this._state.setText(this.getAttribute('text') ?? '');
|
|
164
161
|
this._renderTitle();
|
|
165
162
|
|
|
@@ -181,6 +178,7 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
181
178
|
this._lastText = this._state.text;
|
|
182
179
|
this._lastLength = this._state.textLength;
|
|
183
180
|
this._render(this._state.state);
|
|
181
|
+
applyRowTooltip(this, this._tooltipParts());
|
|
184
182
|
this._state.subscribe((state) => this._onStateChanged(state));
|
|
185
183
|
}
|
|
186
184
|
|
|
@@ -200,14 +198,26 @@ export class AdwEntryRow extends HTMLElement {
|
|
|
200
198
|
this._state.setMaxLength(Number.parseInt(value ?? '', 10));
|
|
201
199
|
break;
|
|
202
200
|
case 'show-apply-button':
|
|
203
|
-
this._state.setShowApplyButton(
|
|
201
|
+
this._state.setShowApplyButton(booleanAttribute(value, false));
|
|
204
202
|
break;
|
|
205
203
|
case 'activates-default':
|
|
206
|
-
this._state.setActivatesDefault(
|
|
204
|
+
this._state.setActivatesDefault(booleanAttribute(value, false));
|
|
205
|
+
break;
|
|
206
|
+
case 'tooltip-text':
|
|
207
|
+
applyRowTooltip(this, this._tooltipParts());
|
|
207
208
|
break;
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
/**
|
|
213
|
+
* The parts `tooltip-text` lands on: the two slots and the editable area — NOT the
|
|
214
|
+
* apply button or the indicator, which carry tooltips of their own that the consumer
|
|
215
|
+
* reads for what they are.
|
|
216
|
+
*/
|
|
217
|
+
private _tooltipParts(): readonly Element[] {
|
|
218
|
+
return [this._prefixes, this._area, this._suffixes];
|
|
219
|
+
}
|
|
220
|
+
|
|
211
221
|
/**
|
|
212
222
|
* Add a widget after the editable area — `adw_entry_row_add_suffix`, which APPENDS
|
|
213
223
|
* into a box, so several suffixes coexist and the password row's own peek toggle
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// <adw-expander-row> — a boxed-list row that discloses nested rows when expanded,
|
|
2
2
|
// with an optional enable switch. Mirrors Adw.ExpanderRow.
|
|
3
3
|
//
|
|
4
|
+
// ATTRIBUTES: `title`, `subtitle`, `expanded`, `enable-expansion`, `show-enable-switch`,
|
|
5
|
+
// and `title-lines` / `subtitle-lines` — clamp either label to N lines, `0` = unlimited,
|
|
6
|
+
// the AdwActionRow pspec's sentinel (`@girs/adw-1`, min 0, default 0).
|
|
7
|
+
// `tooltip-text` (`Gtk.Widget:tooltip-text`) — on the HEADER row alone, which is the
|
|
8
|
+
// part that is the row libadwaita draws.
|
|
9
|
+
//
|
|
4
10
|
// Slots: `slot="prefix"` / `slot="suffix"` children sit in the HEADER row beside the
|
|
5
11
|
// title (before the enable switch and disclosure chevron), like Adw.ExpanderRow's
|
|
6
12
|
// add_prefix/add_suffix; every other child is moved into the disclosed content
|
|
@@ -22,7 +28,9 @@
|
|
|
22
28
|
import { ExpanderState, deriveRowLabels } from '@gjsify/adwaita-core';
|
|
23
29
|
|
|
24
30
|
import { bindEmptySections } from '../empty-sections.js';
|
|
31
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
25
32
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
33
|
+
import { applyRowLineClamp, parseRowLinesAttribute } from '../row-line-clamp.js';
|
|
26
34
|
|
|
27
35
|
// SIDE-EFFECT import, deliberately separate from the type import below: it guarantees
|
|
28
36
|
// `gtk-switch` is defined before this module's `customElements.define` can upgrade a
|
|
@@ -68,7 +76,16 @@ export class AdwExpanderRow extends HTMLElement {
|
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
static get observedAttributes() {
|
|
71
|
-
return [
|
|
79
|
+
return [
|
|
80
|
+
'title',
|
|
81
|
+
'subtitle',
|
|
82
|
+
'expanded',
|
|
83
|
+
'enable-expansion',
|
|
84
|
+
'show-enable-switch',
|
|
85
|
+
'tooltip-text',
|
|
86
|
+
'title-lines',
|
|
87
|
+
'subtitle-lines',
|
|
88
|
+
];
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
get expanded(): boolean {
|
|
@@ -224,6 +241,22 @@ export class AdwExpanderRow extends HTMLElement {
|
|
|
224
241
|
// step with the flag; `aria-expanded` is the same statement to the same reader.
|
|
225
242
|
this._headerEl.setAttribute('aria-expanded', String(this.expanded));
|
|
226
243
|
this._contentEl.classList.toggle('expanded', this.expanded);
|
|
244
|
+
// The HEADER only, not the disclosure: libadwaita's tooltip belongs to the row, and
|
|
245
|
+
// the content box is where the disclosed rows live — a child row's own tooltip is
|
|
246
|
+
// what the browser should offer there.
|
|
247
|
+
applyRowTooltip(this, [this._headerEl]);
|
|
248
|
+
this._applyLineClamping();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Apply CSS line-clamping based on title-lines/subtitle-lines attributes. */
|
|
252
|
+
private _applyLineClamping(): void {
|
|
253
|
+
applyRowLineClamp({
|
|
254
|
+
titleEl: this._titleEl,
|
|
255
|
+
subtitleEl: this._subtitleEl,
|
|
256
|
+
textContainerEl: this._titleEl.parentElement!,
|
|
257
|
+
getTitleLines: () => parseRowLinesAttribute(this.getAttribute('title-lines')),
|
|
258
|
+
getSubtitleLines: () => parseRowLinesAttribute(this.getAttribute('subtitle-lines')),
|
|
259
|
+
});
|
|
227
260
|
}
|
|
228
261
|
}
|
|
229
262
|
|
|
@@ -53,6 +53,12 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
53
53
|
* bare `Adw.HeaderBar {}` in a `.blp` page shows "Mailboxes" with no title of its own.
|
|
54
54
|
*/
|
|
55
55
|
private _page: Element | null = null;
|
|
56
|
+
/**
|
|
57
|
+
* The window the bar sits in: `update_title`'s last stop before the application name
|
|
58
|
+
* (`gtk_window_get_title` of the root), so a bar with no title of its own, under no titled
|
|
59
|
+
* page, shows the window's.
|
|
60
|
+
*/
|
|
61
|
+
private _window: Element | null = null;
|
|
56
62
|
private _pageObserver: MutationObserver | null = null;
|
|
57
63
|
|
|
58
64
|
static get observedAttributes() {
|
|
@@ -136,6 +142,7 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
136
142
|
this._pageObserver?.disconnect();
|
|
137
143
|
this._pageObserver = null;
|
|
138
144
|
this._page = null;
|
|
145
|
+
this._window = null;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
/**
|
|
@@ -146,9 +153,12 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
146
153
|
*/
|
|
147
154
|
private _followPage() {
|
|
148
155
|
this._page = this.closest('adw-navigation-page');
|
|
149
|
-
|
|
156
|
+
this._window = this.closest('adw-window, adw-application-window');
|
|
150
157
|
this._pageObserver ??= new MutationObserver(() => this._renderTitle());
|
|
151
|
-
|
|
158
|
+
for (const ancestor of [this._page, this._window]) {
|
|
159
|
+
if (ancestor !== null)
|
|
160
|
+
this._pageObserver.observe(ancestor, { attributes: true, attributeFilter: ['title'] });
|
|
161
|
+
}
|
|
152
162
|
}
|
|
153
163
|
|
|
154
164
|
/**
|
|
@@ -188,9 +198,13 @@ export class AdwHeaderBar extends HTMLElement {
|
|
|
188
198
|
// keeps "unset" distinguishable from "set to empty" on the child.
|
|
189
199
|
for (const name of ['title', 'subtitle']) {
|
|
190
200
|
// The bar's own `title` is this port's declarative divergence (see the header) and
|
|
191
|
-
// wins; without one, the page's title is the first answer `update_title` has
|
|
201
|
+
// wins; without one, the page's title is the first answer `update_title` has, then
|
|
202
|
+
// the window's.
|
|
192
203
|
const value =
|
|
193
|
-
this.getAttribute(name) ??
|
|
204
|
+
this.getAttribute(name) ??
|
|
205
|
+
(name === 'title'
|
|
206
|
+
? (this._page?.getAttribute('title') ?? this._window?.getAttribute('title') ?? null)
|
|
207
|
+
: null);
|
|
194
208
|
if (value === null) this._titleEl.removeAttribute(name);
|
|
195
209
|
else this._titleEl.setAttribute(name, value);
|
|
196
210
|
}
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '@gjsify/adwaita-core';
|
|
27
27
|
|
|
28
28
|
import { bindBreakpointSetter } from '../breakpoints.js';
|
|
29
|
+
import type { DispatchedSignals } from '../signals.js';
|
|
29
30
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -80,6 +81,9 @@ function readTriStateAttr(element: Element, name: string, fallback: boolean): bo
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
export class AdwOverlaySplitView extends HTMLElement {
|
|
84
|
+
/** The GTK signals this element dispatches, which is what a `.blp` `bind` of `show-sidebar` follows. */
|
|
85
|
+
static readonly signals: DispatchedSignals = { 'notify::show-sidebar': 'notify::show-sidebar' };
|
|
86
|
+
|
|
83
87
|
private _initialized = false;
|
|
84
88
|
private _sidebarEl!: HTMLDivElement;
|
|
85
89
|
private _contentEl!: HTMLDivElement;
|
|
@@ -97,6 +101,8 @@ export class AdwOverlaySplitView extends HTMLElement {
|
|
|
97
101
|
* `show-sidebar` + `pin-sidebar` mean together, held to `OVERLAY_COLLAPSE_VECTORS`.
|
|
98
102
|
*/
|
|
99
103
|
private _state = new OverlaySplitViewState();
|
|
104
|
+
/** The `show-sidebar` the last `notify::show-sidebar` (or the first read) settled on. */
|
|
105
|
+
private _notifiedShowSidebar: boolean | null = null;
|
|
100
106
|
/** Re-entrancy guard for {@link _reflectShowSidebar}. */
|
|
101
107
|
private _reflecting = false;
|
|
102
108
|
/** The view's own width in CSS px — the size the sidebar fraction is OF. */
|
|
@@ -329,13 +335,30 @@ export class AdwOverlaySplitView extends HTMLElement {
|
|
|
329
335
|
private _reflectShowSidebar() {
|
|
330
336
|
if (this._reflecting) return;
|
|
331
337
|
const wanted = this._state.showSidebar ? '' : 'false';
|
|
332
|
-
if (this.getAttribute('show-sidebar')
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
+
if (this.getAttribute('show-sidebar') !== wanted) {
|
|
339
|
+
this._reflecting = true;
|
|
340
|
+
try {
|
|
341
|
+
this.setAttribute('show-sidebar', wanted);
|
|
342
|
+
} finally {
|
|
343
|
+
this._reflecting = false;
|
|
344
|
+
}
|
|
338
345
|
}
|
|
346
|
+
this._notifyShowSidebar();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* `notify::show-sidebar`, raised on the EFFECTIVE value — the state's, after an auto-hide on
|
|
351
|
+
* collapse — and only when it changed, the way GObject notifies. Every path that moves it
|
|
352
|
+
* (the attribute, the property, a breakpoint, a gesture) ends in {@link _reflectShowSidebar},
|
|
353
|
+
* so this is the one place it is raised. The first read only records the baseline: a bind
|
|
354
|
+
* reads the current value itself.
|
|
355
|
+
*/
|
|
356
|
+
private _notifyShowSidebar() {
|
|
357
|
+
const shown = this._state.showSidebar;
|
|
358
|
+
const previous = this._notifiedShowSidebar;
|
|
359
|
+
this._notifiedShowSidebar = shown;
|
|
360
|
+
if (previous === null || previous === shown) return;
|
|
361
|
+
this.dispatchEvent(new CustomEvent('notify::show-sidebar', { bubbles: true, detail: { showSidebar: shown } }));
|
|
339
362
|
}
|
|
340
363
|
|
|
341
364
|
private _syncBreakpoint() {
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// FOUR PROPERTIES, AND EVERY ONE OF THEM IS ABOUT THE TITLE LABEL:
|
|
6
6
|
// `title` (Pango markup unless `use-markup` is FALSE), `use-markup`, `use-underline`
|
|
7
7
|
// (an embedded `_` marks a mnemonic) and `title-selectable` (the user may copy it) —
|
|
8
|
-
// the property docs are at adw-preferences-row.c:118-170.
|
|
8
|
+
// the property docs are at adw-preferences-row.c:118-170. Inherited from `GtkWidget`,
|
|
9
|
+
// every row also takes `tooltip-text` (`src/row-tooltip.ts`).
|
|
9
10
|
//
|
|
10
11
|
// ONE DELIBERATE PORT DECISION, named here because C says the opposite in so many
|
|
11
12
|
// words: "It doesn't present the title in any way and lets you present the preference
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
|
|
44
45
|
import { labelDisplayText, stringIsNotEmpty } from '@gjsify/adwaita-core';
|
|
45
46
|
|
|
47
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
46
48
|
import { bindEmptySections } from '../empty-sections.js';
|
|
47
49
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
48
50
|
|
|
@@ -52,7 +54,7 @@ export class AdwPreferencesRow extends HTMLElement {
|
|
|
52
54
|
private _initialized = false;
|
|
53
55
|
|
|
54
56
|
static get observedAttributes() {
|
|
55
|
-
return ['title', 'title-selectable', 'use-markup', 'use-underline'];
|
|
57
|
+
return ['title', 'title-selectable', 'use-markup', 'use-underline', 'tooltip-text'];
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
/** `Adw.PreferencesRow:title` — Pango markup unless {@link useMarkup} is false. */
|
|
@@ -144,6 +146,7 @@ export class AdwPreferencesRow extends HTMLElement {
|
|
|
144
146
|
// `Gtk.Label:selectable` puts a label in GTK_SELECTION_TEXT; the DOM's spelling
|
|
145
147
|
// of "this text may be copied" is `user-select: text`.
|
|
146
148
|
this._titleEl.style.userSelect = this.titleSelectable ? 'text' : '';
|
|
149
|
+
applyRowTooltip(this, [this._titleEl, this._contentEl]);
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
|
|
65
65
|
import { createGtkImage } from './gtk-image.js';
|
|
66
66
|
import { attachRovingFocus } from './roving-focus.js';
|
|
67
|
+
import { booleanAttribute } from '../attributes.js';
|
|
67
68
|
|
|
68
69
|
// The sidebar consumes its declared children and drops them from the tree, so a later
|
|
69
70
|
// `setAttribute` on one cannot find its sidebar with `closest()`. These keep the link —
|
|
@@ -75,28 +76,51 @@ const sectionBindings = new WeakMap<AdwSidebarSection, { sidebar: AdwSidebar; sp
|
|
|
75
76
|
/** A single sidebar item. Child of <adw-sidebar-section>; consumed at connect time. */
|
|
76
77
|
export class AdwSidebarItem extends HTMLElement {
|
|
77
78
|
static get observedAttributes() {
|
|
78
|
-
return [
|
|
79
|
+
return [
|
|
80
|
+
'title',
|
|
81
|
+
'subtitle',
|
|
82
|
+
'icon-name',
|
|
83
|
+
'disabled',
|
|
84
|
+
'hidden',
|
|
85
|
+
'enabled',
|
|
86
|
+
'visible',
|
|
87
|
+
'needs-attention',
|
|
88
|
+
'badge-number',
|
|
89
|
+
];
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
/**
|
|
82
|
-
* `AdwSidebarItem:enabled`, under the GIR name — the `disabled` attribute inverted.
|
|
83
|
-
* property is what lets an authored `enabled: false` reach this item through the
|
|
93
|
+
* `AdwSidebarItem:enabled`, under the GIR name — the `disabled` attribute inverted.
|
|
94
|
+
* The property is what lets an authored `enabled: false` reach this item through the
|
|
84
95
|
* shared-tree builder, which writes a `false` through the element's own property.
|
|
96
|
+
* Reads both the presence-based `disabled` and value-based `enabled` attributes.
|
|
85
97
|
*/
|
|
86
98
|
get enabled(): boolean {
|
|
99
|
+
// Value-based `enabled` attribute takes precedence (shared-tree builder writes it).
|
|
100
|
+
const enabledAttr = this.getAttribute('enabled');
|
|
101
|
+
if (enabledAttr !== null) return booleanAttribute(enabledAttr, true);
|
|
102
|
+
// Fall back to presence-based `disabled` attribute.
|
|
87
103
|
return !this.hasAttribute('disabled');
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
set enabled(value: boolean) {
|
|
107
|
+
// Write both for compatibility: value-based `enabled` and presence-based `disabled`.
|
|
108
|
+
this.setAttribute('enabled', value ? 'true' : 'false');
|
|
91
109
|
this.toggleAttribute('disabled', !value);
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
/** `AdwSidebarItem:visible` — the `hidden` attribute inverted, for the same reason. */
|
|
95
113
|
get visible(): boolean {
|
|
114
|
+
// Value-based `visible` attribute takes precedence (shared-tree builder writes it).
|
|
115
|
+
const visibleAttr = this.getAttribute('visible');
|
|
116
|
+
if (visibleAttr !== null) return booleanAttribute(visibleAttr, true);
|
|
117
|
+
// Fall back to presence-based `hidden` attribute.
|
|
96
118
|
return !this.hasAttribute('hidden');
|
|
97
119
|
}
|
|
98
120
|
|
|
99
121
|
set visible(value: boolean) {
|
|
122
|
+
// Write both for compatibility: value-based `visible` and presence-based `hidden`.
|
|
123
|
+
this.setAttribute('visible', value ? 'true' : 'false');
|
|
100
124
|
this.toggleAttribute('hidden', !value);
|
|
101
125
|
}
|
|
102
126
|
|
|
@@ -109,7 +133,9 @@ export class AdwSidebarItem extends HTMLElement {
|
|
|
109
133
|
else if (name === 'subtitle') binding.spec.subtitle = value;
|
|
110
134
|
else if (name === 'icon-name') binding.spec.iconName = value;
|
|
111
135
|
else if (name === 'disabled') binding.spec.enabled = newValue === null;
|
|
136
|
+
else if (name === 'enabled') binding.spec.enabled = booleanAttribute(newValue, true);
|
|
112
137
|
else if (name === 'hidden') binding.spec.visible = newValue === null;
|
|
138
|
+
else if (name === 'visible') binding.spec.visible = booleanAttribute(newValue, true);
|
|
113
139
|
else if (name === 'needs-attention') binding.spec.needsAttention = newValue === null;
|
|
114
140
|
else if (name === 'badge-number') binding.spec.badgeNumber = Number.parseInt(value, 10) || 0;
|
|
115
141
|
|
|
@@ -263,8 +289,10 @@ export class AdwSidebar extends HTMLElement {
|
|
|
263
289
|
title: itemEl.getAttribute('title') ?? '',
|
|
264
290
|
subtitle: itemEl.getAttribute('subtitle') ?? '',
|
|
265
291
|
iconName: itemEl.getAttribute('icon-name') ?? '',
|
|
266
|
-
|
|
267
|
-
visible
|
|
292
|
+
// Use the element's own property getters, which read both value-based
|
|
293
|
+
// (`enabled`/`visible`) and presence-based (`disabled`/`hidden`) attributes.
|
|
294
|
+
enabled: itemEl.enabled,
|
|
295
|
+
visible: itemEl.visible,
|
|
268
296
|
badgeNumber: Number.parseInt(itemEl.getAttribute('badge-number') ?? '0', 10) || 0,
|
|
269
297
|
needsAttention: itemEl.hasAttribute('needs-attention'),
|
|
270
298
|
};
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
// `adjustment:` sets the property to a whole new object: an unwritten field takes the
|
|
25
25
|
// adjustment's own default, not what the row held (`ADJUSTMENT_AUTHORED_VECTORS`).
|
|
26
26
|
//
|
|
27
|
+
// ATTRIBUTES: `adjustment` (the range, JSON), `value`, `title`, `subtitle`, and
|
|
28
|
+
// `title-lines` / `subtitle-lines` — clamp either label to N lines, `0` = unlimited,
|
|
29
|
+
// the AdwActionRow pspec's sentinel (`@girs/adw-1`, min 0, default 0).
|
|
30
|
+
// `tooltip-text` (`Gtk.Widget:tooltip-text`) — the row's tooltip (`src/row-tooltip.ts`).
|
|
31
|
+
|
|
27
32
|
// Adapted from Adwaita Web UI Framework (https://github.com/mclellac/adwaita-web).
|
|
28
33
|
// Copyright (c) 2025 csm. MIT License.
|
|
29
34
|
// Modifications: Reimplemented as Web Component for @gjsify/adwaita-web;
|
|
@@ -34,7 +39,9 @@ import { SpinState, deriveRowLabels, normalizeAdjustment, parseAdjustment } from
|
|
|
34
39
|
import type { AdwAdjustment, AdwAdjustmentInput } from '@gjsify/adwaita-core';
|
|
35
40
|
import { attributeOf } from '@gjsify/adwaita-core/tags';
|
|
36
41
|
|
|
42
|
+
import { applyRowTooltip } from '../row-tooltip.js';
|
|
37
43
|
import { bindSlottedChildren } from '../slotted-children.js';
|
|
44
|
+
import { applyRowLineClamp, parseRowLinesAttribute } from '../row-line-clamp.js';
|
|
38
45
|
|
|
39
46
|
/** `Gtk.Adjustment`'s six properties, as `AdwAdjustmentInput` names them. */
|
|
40
47
|
const ADJUSTMENT_FIELDS = ['value', 'lower', 'upper', 'stepIncrement', 'pageIncrement', 'pageSize'] as const;
|
|
@@ -58,6 +65,10 @@ function authoredAdjustment(node: Node): AdwAdjustmentInput {
|
|
|
58
65
|
|
|
59
66
|
export class AdwSpinRow extends HTMLElement {
|
|
60
67
|
private _input!: HTMLInputElement;
|
|
68
|
+
/** The label column — kept for `tooltip-text`, which the browser reads off a PART. */
|
|
69
|
+
private _textEl!: HTMLDivElement;
|
|
70
|
+
/** The −/input/+ box — the other half of the row's surface. */
|
|
71
|
+
private _controlEl!: HTMLDivElement;
|
|
61
72
|
private _titleEl!: HTMLSpanElement;
|
|
62
73
|
private _subtitleEl!: HTMLSpanElement;
|
|
63
74
|
/** The headless adjustment: the range, the clamp and the two signals (ADR 0004, ADR 0047). */
|
|
@@ -65,7 +76,7 @@ export class AdwSpinRow extends HTMLElement {
|
|
|
65
76
|
private _initialized = false;
|
|
66
77
|
|
|
67
78
|
static get observedAttributes() {
|
|
68
|
-
return ['title', 'subtitle', 'value', 'adjustment'];
|
|
79
|
+
return ['title', 'subtitle', 'value', 'adjustment', 'tooltip-text', 'title-lines', 'subtitle-lines'];
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
get value(): number {
|
|
@@ -107,6 +118,7 @@ export class AdwSpinRow extends HTMLElement {
|
|
|
107
118
|
|
|
108
119
|
const text = document.createElement('div');
|
|
109
120
|
text.className = 'adw-row-text';
|
|
121
|
+
this._textEl = text;
|
|
110
122
|
this._titleEl = document.createElement('span');
|
|
111
123
|
this._titleEl.className = 'adw-row-title';
|
|
112
124
|
this._subtitleEl = document.createElement('span');
|
|
@@ -115,6 +127,7 @@ export class AdwSpinRow extends HTMLElement {
|
|
|
115
127
|
|
|
116
128
|
const control = document.createElement('div');
|
|
117
129
|
control.className = 'adw-spin-control';
|
|
130
|
+
this._controlEl = control;
|
|
118
131
|
|
|
119
132
|
const decBtn = document.createElement('button');
|
|
120
133
|
decBtn.className = 'adw-spin-dec';
|
|
@@ -164,7 +177,16 @@ export class AdwSpinRow extends HTMLElement {
|
|
|
164
177
|
|
|
165
178
|
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
|
166
179
|
if (!this._initialized) return;
|
|
167
|
-
if (
|
|
180
|
+
if (
|
|
181
|
+
name === 'title' ||
|
|
182
|
+
name === 'subtitle' ||
|
|
183
|
+
name === 'tooltip-text' ||
|
|
184
|
+
// The two `*-lines` attributes are LABEL geometry, not the adjustment: without
|
|
185
|
+
// this branch they fell through to the `setValue` below, so `title-lines="1"`
|
|
186
|
+
// set the numeric value to 1 and clamped nothing.
|
|
187
|
+
name === 'title-lines' ||
|
|
188
|
+
name === 'subtitle-lines'
|
|
189
|
+
) {
|
|
168
190
|
this._renderText();
|
|
169
191
|
return;
|
|
170
192
|
}
|
|
@@ -186,6 +208,19 @@ export class AdwSpinRow extends HTMLElement {
|
|
|
186
208
|
this._titleEl.hidden = !labels.titleVisible;
|
|
187
209
|
this._subtitleEl.textContent = labels.subtitle;
|
|
188
210
|
this._subtitleEl.hidden = !labels.subtitleVisible;
|
|
211
|
+
applyRowTooltip(this, [this._textEl, this._controlEl]);
|
|
212
|
+
this._applyLineClamping();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Apply CSS line-clamping based on title-lines/subtitle-lines attributes. */
|
|
216
|
+
private _applyLineClamping(): void {
|
|
217
|
+
applyRowLineClamp({
|
|
218
|
+
titleEl: this._titleEl,
|
|
219
|
+
subtitleEl: this._subtitleEl,
|
|
220
|
+
textContainerEl: this._titleEl.parentElement!,
|
|
221
|
+
getTitleLines: () => parseRowLinesAttribute(this.getAttribute('title-lines')),
|
|
222
|
+
getSubtitleLines: () => parseRowLinesAttribute(this.getAttribute('subtitle-lines')),
|
|
223
|
+
});
|
|
189
224
|
}
|
|
190
225
|
|
|
191
226
|
/** A stepper press — the interactive path, so it emits `notify::value`. */
|
|
@@ -57,6 +57,7 @@ import type {
|
|
|
57
57
|
SplitButtonChange,
|
|
58
58
|
SplitButtonDirection,
|
|
59
59
|
} from '@gjsify/adwaita-core';
|
|
60
|
+
import { activateElementMenuItem, menuActionsOfElement } from '../application.js';
|
|
60
61
|
|
|
61
62
|
import { PopoverMenuView } from './popover-menu.js';
|
|
62
63
|
|
|
@@ -336,6 +337,7 @@ export class AdwSplitButton extends HTMLElement {
|
|
|
336
337
|
this._menuView = new PopoverMenuView(this._menuEl, 'adw-split-button-menu', (path) => {
|
|
337
338
|
const activated = this._state.activateMenuItem(path);
|
|
338
339
|
if (activated === null) return;
|
|
340
|
+
activateElementMenuItem(this, activated);
|
|
339
341
|
this.dispatchEvent(
|
|
340
342
|
new CustomEvent('menu-activated', {
|
|
341
343
|
bubbles: true,
|
|
@@ -525,7 +527,9 @@ export class AdwSplitButton extends HTMLElement {
|
|
|
525
527
|
|
|
526
528
|
private _renderMenu(): void {
|
|
527
529
|
this._menuEl.open = this._state.open;
|
|
528
|
-
this.
|
|
530
|
+
const model = this._state.menuModel ?? [];
|
|
531
|
+
this._menuView.setMenuModel(model);
|
|
532
|
+
this._menuView.setActions(this._actions ?? menuActionsOfElement(this, model));
|
|
529
533
|
this._menuView.render();
|
|
530
534
|
}
|
|
531
535
|
}
|