@gjsify/adwaita-web 0.47.0 → 0.48.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.
@@ -1,3 +1,4 @@
1
+ import type { AdwComboOption, AdwListModelInput } from '@gjsify/adwaita-core';
1
2
  export declare class AdwComboRow extends HTMLElement {
2
3
  private _select;
3
4
  private _valueEl;
@@ -7,10 +8,65 @@ export declare class AdwComboRow extends HTMLElement {
7
8
  private readonly _state;
8
9
  private _initialized;
9
10
  static get observedAttributes(): string[];
11
+ /** The list model (`Adw.ComboRow:model`). Setting it splices the <select> and clamps the selection. */
12
+ get model(): AdwComboOption[];
13
+ set model(value: AdwListModelInput);
14
+ /**
15
+ * The selected index (Adw.ComboRow:selected). PERMISSIVE: an index past the end is
16
+ * accepted and reads back with an empty {@link selectedValue}, mirroring the `guint`
17
+ * property that takes any position — where `<gtk-drop-down>` rejects the same set, as
18
+ * its own docs promise. `ComboState.hasIndex` owns the bounds and records why the
19
+ * POLICY is each renderer's; `COMBO_SELECTION_VECTORS` drives both answers.
20
+ */
10
21
  get selected(): number;
11
22
  set selected(value: number);
23
+ /**
24
+ * The selected option's `value`, or '' when nothing is selected (Adw.ComboRow:selected-item).
25
+ *
26
+ * Assigning routes through `selected`, i.e. through the attribute, so a set BY VALUE
27
+ * and a set BY INDEX leave the element in the same observable state — including the
28
+ * reflected `selected=` a consumer or a stylesheet may be reading. An unknown value is
29
+ * a no-op, as on `<gtk-drop-down>`.
30
+ */
31
+ get selectedValue(): string;
32
+ set selectedValue(value: string);
33
+ /**
34
+ * The selected option descriptor, or `null` (Adw.ComboRow:selected-item).
35
+ *
36
+ * Read-only, as the GObject property is. `null` and not a blank descriptor: the
37
+ * sentinel and an index past the end both address no option, and inventing an empty
38
+ * one would make "nothing is selected" indistinguishable from an option with no text.
39
+ */
40
+ get selectedItem(): AdwComboOption | null;
12
41
  connectedCallback(): void;
13
42
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
43
+ /**
44
+ * Build one `<option>` for a model item.
45
+ *
46
+ * ITS `value` IS THE MODEL'S value, not the position. The position used to be written
47
+ * there with a comment defending it, and nothing in this package or its consumers ever
48
+ * read it back — while it made every insertion renumber the whole tail, which is the
49
+ * one thing a splice exists to avoid. The element still addresses its model by
50
+ * POSITION (`selectedIndex`); what the attribute now carries is the descriptor's own
51
+ * value, which is also what a form submission would have wanted.
52
+ */
53
+ private _createOption;
54
+ /**
55
+ * Apply one `items-changed` to the `<option>` list — remove `removed` nodes at
56
+ * `position`, insert `added` fresh ones there, touch nothing else.
57
+ *
58
+ * A no-op before `connectedCallback` has built the DOM, which is what lets `model` be
59
+ * assigned to a detached element: the state keeps the model and the connect path
60
+ * renders it whole.
61
+ */
62
+ private _applyItemsChanged;
63
+ /**
64
+ * Build the whole `<option>` list — the CONNECT path only, where there is no previous
65
+ * list to splice against.
66
+ *
67
+ * Every later assignment goes through {@link _applyItemsChanged}.
68
+ */
69
+ private _renderOptions;
14
70
  /**
15
71
  * `model_changed`: one option or none is not a choice, so the arrow goes and the row
16
72
  * stops being activatable.
@@ -1,13 +1,23 @@
1
+ import type { AdwAdjustment, AdwAdjustmentInput } from '@gjsify/adwaita-core';
1
2
  export declare class AdwSpinRow extends HTMLElement {
2
3
  private _input;
3
4
  private _titleEl;
4
5
  private _subtitleEl;
5
- /** The headless value/min/max/step adjustment with clamping (ADR 0004). */
6
+ /** The headless adjustment: the range, the clamp and the two signals (ADR 0004, ADR 0047). */
6
7
  private readonly _state;
7
8
  private _initialized;
8
9
  static get observedAttributes(): string[];
9
10
  get value(): number;
10
11
  set value(v: number);
12
+ /**
13
+ * The numeric range — `Adw.SpinRow:adjustment`, as the portable value.
14
+ *
15
+ * Reads back whole; writes MERGE, so `el.adjustment = { upper: 20 }` moves one bound
16
+ * and leaves the value where it is. A string is read as the JSON the attribute carries,
17
+ * so the property and the attribute mean the same thing.
18
+ */
19
+ get adjustment(): AdwAdjustment;
20
+ set adjustment(v: AdwAdjustmentInput | string);
11
21
  connectedCallback(): void;
12
22
  attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
13
23
  private _renderText;
@@ -1,4 +1,4 @@
1
- import type { AdwMenuEntry, SplitButtonDirection } from '@gjsify/adwaita-core';
1
+ import type { AdwMenuActions, AdwMenuInput, AdwMenuModel, SplitButtonDirection } from '@gjsify/adwaita-core';
2
2
  import './gtk-popover.js';
3
3
  export declare class AdwSplitButton extends HTMLElement {
4
4
  private readonly _state;
@@ -6,6 +6,8 @@ export declare class AdwSplitButton extends HTMLElement {
6
6
  private _dropdownEl;
7
7
  private _arrowEl;
8
8
  private _menuEl;
9
+ private _menuView;
10
+ private _actions;
9
11
  /** Inline text content, captured before we take over the subtree. */
10
12
  private _inlineLabel;
11
13
  /** Last `open` value reflected as `notify::active`, so the event fires once per flip. */
@@ -21,8 +23,46 @@ export declare class AdwSplitButton extends HTMLElement {
21
23
  /** The symbolic icon name, or `null` when the action half shows a label or nothing. */
22
24
  get iconName(): string | null;
23
25
  set iconName(value: string);
24
- get menuItems(): readonly AdwMenuEntry[];
25
- set menuItems(value: readonly AdwMenuEntry[]);
26
+ /** The menu, normalised (ADR 0042). Empty when the dropdown has none. */
27
+ get menuModel(): AdwMenuModel;
28
+ /**
29
+ * Set the menu from anything the portable model accepts — a bare `string[]`, item
30
+ * descriptors, sections, submenus.
31
+ *
32
+ * The REFUSAL is here rather than at render time: a `custom` item names an
33
+ * application widget this surface cannot host, and discovering that as a blank row
34
+ * three interactions later is what {@link assertMenuRenderable} exists to prevent.
35
+ */
36
+ set menuModel(value: AdwMenuInput);
37
+ /**
38
+ * Normalise, REFUSE, store — the one door every menu comes through.
39
+ *
40
+ * The property setter is not the only way a menu arrives: an attribute is, and the
41
+ * first cut refused only the setter, so a `custom` item written in markup drew
42
+ * exactly the row `assertMenuRenderable` exists to prevent — one that reads like a
43
+ * command and does nothing.
44
+ *
45
+ * THE TWO DOORS REFUSE DIFFERENTLY, and the difference is which side can hear it.
46
+ * A property assignment is a CALL, so it throws and the caller can catch. An
47
+ * attribute is MARKUP, parsed by the browser: a throw from `connectedCallback` is
48
+ * not delivered to whoever appended the element, it is reported as an uncaught
49
+ * page error — measured, it broke `adwaita-upgrade-order.spec.ts`, which counts
50
+ * exactly those. Nobody can handle it and everybody else pays for it. So the
51
+ * attribute path REFUSES THE MENU (no menu, and a menu-less dropdown is
52
+ * insensitive, which is visible) and says why on `console.error`.
53
+ *
54
+ * A REFUSAL AND A TYPO ARE STILL DIFFERENT THINGS. `parseMenuModel` is total
55
+ * because malformed JSON is an author slip and must not stop the element
56
+ * upgrading; `custom` is well-formed, deliberate, and unhonourable here.
57
+ */
58
+ private _acceptMenu;
59
+ /**
60
+ * What the action group publishes about the actions this menu names — the portable
61
+ * stand-in for a `GActionGroup`, and the ONLY place a menu's enabled/checked state
62
+ * can come from (ADR 0042). Setting it re-renders the rows.
63
+ */
64
+ get actions(): AdwMenuActions | null;
65
+ set actions(value: AdwMenuActions | null);
26
66
  /** The dropdown tooltip as set — `''` while unset. */
27
67
  get dropdownTooltip(): string;
28
68
  set dropdownTooltip(value: string);
@@ -1,5 +1,5 @@
1
1
  import './gtk-popover.js';
2
- import type { AdwComboOption, AdwComboOptionInput } from '@gjsify/adwaita-core';
2
+ import type { AdwComboOption, AdwListModelInput } from '@gjsify/adwaita-core';
3
3
  /**
4
4
  * A dropdown option — `value` is the stable id, `label` the shown text. An alias of
5
5
  * core's {@link AdwComboOption}, since the drop-down and the combo row are the same
@@ -19,11 +19,9 @@ export declare class GtkDropDown extends HTMLElement {
19
19
  private _typeAheadBuffer;
20
20
  private _typeAheadTimer;
21
21
  static get observedAttributes(): string[];
22
- /** The options list. Setting it rebuilds the popover and clamps the selection. */
23
- get options(): GtkDropDownOption[];
24
- set options(value: ReadonlyArray<AdwComboOptionInput>);
25
- get items(): GtkDropDownOption[];
26
- set items(value: ReadonlyArray<AdwComboOptionInput>);
22
+ /** The list model (`Gtk.DropDown:model`). Setting it splices the popover and clamps the selection. */
23
+ get model(): GtkDropDownOption[];
24
+ set model(value: AdwListModelInput);
27
25
  /** The selected index. Out-of-range values are ignored (Gtk.DropDown:selected). */
28
26
  get selected(): number;
29
27
  set selected(value: number);
@@ -36,7 +34,6 @@ export declare class GtkDropDown extends HTMLElement {
36
34
  get active(): boolean;
37
35
  connectedCallback(): void;
38
36
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
39
- private _parseOptionsAttr;
40
37
  private _selectIndex;
41
38
  private _onPopoverToggled;
42
39
  private _onButtonKeyDown;
@@ -49,4 +46,22 @@ export declare class GtkDropDown extends HTMLElement {
49
46
  private _updateLabel;
50
47
  private _updateSelectedStates;
51
48
  private _renderPopover;
49
+ /**
50
+ * One row button.
51
+ *
52
+ * The click handler reads the row's CURRENT position out of `_itemButtons` instead of
53
+ * closing over the index it was built at. Under a full rebuild the two were always
54
+ * equal, which is why the closure survived; under a splice they are not, and a row
55
+ * that shifted by one would have selected its neighbour.
56
+ */
57
+ private _createItem;
58
+ /**
59
+ * Apply one `items-changed` to the row list — remove `removed` buttons at `position`,
60
+ * insert `added` fresh ones there, leave every other row (and its focus) standing.
61
+ *
62
+ * It owns everything a model replacement has to refresh, so the property door and the
63
+ * attribute door share one update path: the button label, the per-row selected state,
64
+ * and popping the popover down when the model empties under it.
65
+ */
66
+ private _applyItemsChanged;
52
67
  }
@@ -1,36 +1,53 @@
1
- import type { AdwMenuEntry, SplitButtonDirection } from '@gjsify/adwaita-core';
1
+ import type { AdwMenuActions, AdwMenuInput, AdwMenuModel, SplitButtonDirection } from '@gjsify/adwaita-core';
2
2
  import './gtk-popover.js';
3
- /**
4
- * A menu entry — `@gjsify/adwaita-core`'s {@link AdwMenuEntry} under the name both
5
- * renderers export it as.
6
- *
7
- * IT KEEPS THE `Adw` PREFIX WHILE THE ELEMENT ABOVE IT DOES NOT, and the reason is not
8
- * "the name it has always used" — ADR 0034 clause 1 just moved every name in this file
9
- * that had one. It is that this is not a WIDGET name: clause 1 is about the tag, and
10
- * this is the descriptor a consumer writes menu entries with. `@gjsify/adwaita-
11
- * nativescript` exports `AdwMenuItem` for the same type, and that port deliberately
12
- * keeps `Adw` throughout, so renaming this half would give one object two spellings —
13
- * which is the thing the ADR is removing, not applying. (`GtkDropDownOption` next door
14
- * DID move: its NativeScript twin exports no such name, so there was nothing to split.)
15
- *
16
- * It used to be a SECOND declaration of the same shape, and the NativeScript menu
17
- * button declared a THIRD that was missing `icon` entirely. One type, so a consumer
18
- * writing menu entries writes the same object for either renderer.
19
- */
20
- export type AdwMenuItem = AdwMenuEntry;
21
3
  export declare class GtkMenuButton extends HTMLElement {
22
4
  private _buttonEl;
23
5
  private _popoverEl;
24
- private _items;
6
+ private _model;
7
+ private _actions;
25
8
  private _menuTitle;
26
9
  private _initialized;
27
- private _itemButtons;
10
+ private _menuView;
28
11
  static get observedAttributes(): string[];
29
12
  /** Whether the popover menu is currently open. */
30
13
  get active(): boolean;
31
- /** The menu entries. Setting rebuilds the popover. */
32
- get menuItems(): AdwMenuItem[];
33
- set menuItems(value: AdwMenuItem[]);
14
+ /** The menu, normalised (ADR 0042). Setting rebuilds the popover. */
15
+ get menuModel(): AdwMenuModel;
16
+ /**
17
+ * Set the menu from anything the portable model accepts. Refused HERE, at the
18
+ * assignment, for a `custom` item this surface cannot host — see the split button's
19
+ * note on the same setter.
20
+ */
21
+ set menuModel(value: AdwMenuInput);
22
+ /**
23
+ * Normalise, REFUSE, store — the one door every menu comes through.
24
+ *
25
+ * The property setter is not the only way a menu arrives: an attribute is, and the
26
+ * first cut refused only the setter, so a `custom` item written in markup drew
27
+ * exactly the row `assertMenuRenderable` exists to prevent — one that reads like a
28
+ * command and does nothing.
29
+ *
30
+ * THE TWO DOORS REFUSE DIFFERENTLY, and the difference is which side can hear it.
31
+ * A property assignment is a CALL, so it throws and the caller can catch. An
32
+ * attribute is MARKUP, parsed by the browser: a throw from `connectedCallback` is
33
+ * not delivered to whoever appended the element, it is reported as an uncaught
34
+ * page error — measured, it broke `adwaita-upgrade-order.spec.ts`, which counts
35
+ * exactly those. Nobody can handle it and everybody else pays for it. So the
36
+ * attribute path REFUSES THE MENU (no menu, and a menu-less dropdown is
37
+ * insensitive, which is visible) and says why on `console.error`.
38
+ *
39
+ * A REFUSAL AND A TYPO ARE STILL DIFFERENT THINGS. `parseMenuModel` is total
40
+ * because malformed JSON is an author slip and must not stop the element
41
+ * upgrading; `custom` is well-formed, deliberate, and unhonourable here.
42
+ */
43
+ private _acceptMenu;
44
+ /**
45
+ * What the action group publishes about the actions this menu names — the portable
46
+ * stand-in for a `GActionGroup`, and the only source of a menu's enabled/checked
47
+ * state (ADR 0042).
48
+ */
49
+ get actions(): AdwMenuActions | null;
50
+ set actions(value: AdwMenuActions | null);
34
51
  /** The optional popover heading. */
35
52
  get menuTitle(): string;
36
53
  set menuTitle(value: string);
@@ -40,12 +57,12 @@ export declare class GtkMenuButton extends HTMLElement {
40
57
  connectedCallback(): void;
41
58
  attributeChangedCallback(name: string): void;
42
59
  /**
43
- * The `menu` attribute, through the core parser the split button already used.
60
+ * The `menu-model` attribute, through the core parser both elements share.
44
61
  *
45
62
  * The copy this replaces was weaker in a way markup can reach: it kept `id` and
46
63
  * `icon` WHATEVER their runtime type, so `{"label":"Open","id":7}` produced an
47
64
  * entry whose `id` is a number in a field typed `string` — and `id` is what the
48
- * activation event reports. The core parser keeps only string-typed extras.
65
+ * activation event reports. The core parser keeps only string-typed attributes.
49
66
  */
50
67
  private _parseMenuAttr;
51
68
  private _onPopoverToggled;
@@ -26,7 +26,20 @@ export declare class GtkPopover extends HTMLElement {
26
26
  get align(): GtkPopoverAlign;
27
27
  set align(value: GtkPopoverAlign);
28
28
  get popoverRole(): GtkPopoverRole;
29
- /** The navigable rows, in DOM order. Hidden rows are skipped — a filtered list navigates what it shows. */
29
+ /**
30
+ * The navigable rows, in DOM order.
31
+ *
32
+ * HIDDEN rows are skipped — a filtered list navigates what it shows. DISABLED rows
33
+ * are skipped for a harder reason: a disabled `<button>` cannot take focus at all, so
34
+ * `items[index].focus()` is a NO-OP and the arrow key reads as dead. Keeping one in
35
+ * the walk is the same defect a roving tabindex with no keys behind it has, one row
36
+ * wide — measured on a menu whose action group reported an action disabled
37
+ * (ADR 0042): ArrowDown onto it left `document.activeElement` where it was.
38
+ *
39
+ * GTK skips them for the same reason and says so in the general rule rather than in
40
+ * the menu: `gtk_widget_focus_move` walks only widgets `gtk_widget_get_can_focus`
41
+ * accepts, and an insensitive widget is not one.
42
+ */
30
43
  get items(): HTMLElement[];
31
44
  /** Show the popover — `gtk_popover_popup()`. */
32
45
  popup(): void;
@@ -0,0 +1,99 @@
1
+ import type { AdwMenuActions, AdwMenuModel, AdwMenuPath } from '@gjsify/adwaita-core';
2
+ import type { GtkPopover } from './gtk-popover.js';
3
+ /**
4
+ * Called when the reader chooses an item, with the path that addresses it in the WHOLE
5
+ * model — never the item itself. The element resolves it through its own state, which is
6
+ * what dismisses the menu, so handing over a second copy of the item would give the
7
+ * activation two sources.
8
+ */
9
+ export type PopoverMenuActivate = (path: AdwMenuPath) => void;
10
+ /**
11
+ * The rows of one popover, and which page is showing.
12
+ *
13
+ * A view rather than a function because a submenu is a NAVIGATION: the open page has to
14
+ * survive between renders, and it has to reset when the popover closes — a menu that
15
+ * reopens three levels deep is a menu the reader cannot get out of.
16
+ */
17
+ export declare class PopoverMenuView {
18
+ private readonly surface;
19
+ /** Class prefix for the element's own hooks — `adw-menu-button`, `adw-split-button-menu`. */
20
+ private readonly prefix;
21
+ private readonly onActivate;
22
+ private _model;
23
+ private _actions;
24
+ private _title;
25
+ /** The submenu whose items are showing; `[]` is the root page. */
26
+ private _page;
27
+ /** The rows that OPEN a page — what ArrowRight acts on. Rebuilt by every render. */
28
+ private _openers;
29
+ /** The row that LEAVES a page — what ArrowLeft acts on. */
30
+ private _backRow;
31
+ /** The canonical text of the model showing, so an unchanged re-render keeps the page. */
32
+ private _key;
33
+ private _rows;
34
+ constructor(surface: GtkPopover,
35
+ /** Class prefix for the element's own hooks — `adw-menu-button`, `adw-split-button-menu`. */
36
+ prefix: string, onActivate: PopoverMenuActivate);
37
+ /**
38
+ * LEFT and RIGHT, which change the page. Every other key belongs to `<gtk-popover>`.
39
+ *
40
+ * The act is the row's own CLICK, not a second copy of what opening a page means:
41
+ * `switch_menu` is one behaviour in GTK too, reached by a pointer and by a direction
42
+ * alike. `preventDefault` before it, for the reason the popover's own Enter handler
43
+ * gives — a focused `<button>` would otherwise also activate natively.
44
+ */
45
+ private _onKeyDown;
46
+ /** Every row of the open page, in order — including the ones no key can reach. */
47
+ get rows(): readonly HTMLButtonElement[];
48
+ /**
49
+ * The rows a key can actually REACH, which is the only list worth focusing into.
50
+ *
51
+ * A hidden row is not rendered and a DISABLED one cannot take focus, so
52
+ * `element.focus()` on either is a silent no-op — and a no-op after `render()` has
53
+ * replaced the row that had focus leaves `document.activeElement` on `<body>`,
54
+ * OUTSIDE an open popover. Measured under real keys: Tab then walked to the control
55
+ * BEHIND the popup and every arrow was dead, because both keydown listeners are
56
+ * element-scoped and the event no longer fired inside either. Escape was the only
57
+ * way out.
58
+ *
59
+ * The predicate lived in the two ELEMENTS (their open path) and not in the two page
60
+ * changes here, which is how it came to be applied in two places out of four. One
61
+ * list, so there is no fourth place to forget.
62
+ */
63
+ get focusableRows(): readonly HTMLButtonElement[];
64
+ /**
65
+ * Put focus on a page, counting only rows a key can reach.
66
+ *
67
+ * `skip` is how many reachable rows to pass — 1 when ENTERING a submenu, because the
68
+ * back row is reachable and the reader was going to the first item past it. The
69
+ * fallback to the first reachable row is what covers a submenu whose every item is
70
+ * disabled: focus lands on the back row, which is always reachable, and the reader
71
+ * can still leave with Left, Enter or Escape.
72
+ */
73
+ private focusPage;
74
+ /**
75
+ * Named for the value it takes, and NOT `setModel` — the portable LIST model gave
76
+ * `ComboState` a `setModel` (ADR 0046), and two methods called `setModel` over two
77
+ * unrelated values on one surface is the collision the vocabulary work exists to
78
+ * remove. It also un-blinds `check-adwaita-collection-reactivity`, which resolves a
79
+ * collection call by the setter's name.
80
+ */
81
+ setMenuModel(model: AdwMenuModel): void;
82
+ setActions(actions: AdwMenuActions | null): void;
83
+ setTitle(title: string): void;
84
+ /** Return to the root page — called when the popover closes. */
85
+ reset(): void;
86
+ /** The items of the page currently showing. */
87
+ private currentItems;
88
+ /** Rebuild the surface's children from the model. */
89
+ render(): void;
90
+ /** The label of the section at `path`, or `null` when it is not a labelled section. */
91
+ private sectionHeading;
92
+ private heading;
93
+ private separator;
94
+ /** A row, with the class that makes `<gtk-popover>` treat it as navigable. */
95
+ private baseRow;
96
+ private backRow;
97
+ private submenuRow;
98
+ private itemRow;
99
+ }
@@ -19,6 +19,6 @@ export { AdwBottomSheetContent, AdwBottomSheetSheet } from './elements/adw-botto
19
19
  export { AdwAlertResponse } from './elements/adw-alert-dialog.js';
20
20
  export type { GtkPopoverAlign, GtkPopoverPosition, GtkPopoverRole } from './elements/gtk-popover.js';
21
21
  export type { AdwViewStackPageInfo } from './elements/adw-view-stack.js';
22
- export type { AdwMenuItem } from './elements/gtk-menu-button.js';
22
+ export type { AdwMenuActions, AdwMenuEntryInput, AdwMenuInput, AdwMenuItem, AdwMenuModel, AdwMenuNode, AdwMenuPath, AdwMenuSection, AdwMenuSubmenu, } from '@gjsify/adwaita-core';
23
23
  export type { GtkDropDownOption } from './elements/gtk-drop-down.js';
24
24
  export type { AdwDialogPresentationMode } from './elements/adw-dialog.js';