@gjsify/adwaita-nativescript 0.64.13 → 0.64.14

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.
Files changed (57) hide show
  1. package/lib/esm/builder/index.js +1 -1
  2. package/lib/esm/index.js +1 -1
  3. package/lib/esm/namespace/gio.js +1 -1
  4. package/lib/esm/namespace/gtk.js +1 -1
  5. package/lib/esm/widgets/adw-about-dialog.js +3 -3
  6. package/lib/esm/widgets/adw-action-row.js +1 -1
  7. package/lib/esm/widgets/adw-button-row.js +1 -1
  8. package/lib/esm/widgets/adw-entry-row.js +1 -1
  9. package/lib/esm/widgets/adw-preferences-group.js +1 -1
  10. package/lib/esm/widgets/adw-split-button.js +1 -1
  11. package/lib/esm/widgets/box-layout.js +1 -1
  12. package/lib/esm/widgets/gtk-box.js +1 -1
  13. package/lib/esm/widgets/gtk-button.js +1 -1
  14. package/lib/esm/widgets/gtk-check-button.js +1 -1
  15. package/lib/esm/widgets/gtk-entry.js +1 -1
  16. package/lib/esm/widgets/gtk-label.js +2 -2
  17. package/lib/esm/widgets/gtk-menu-button.js +1 -1
  18. package/lib/esm/widgets/gtk-popover-menu.js +1 -1
  19. package/lib/esm/widgets/gtk-stack.js +1 -1
  20. package/lib/esm/widgets/index.js +1 -1
  21. package/lib/esm/widgets/label-markup-native.android.js +1 -0
  22. package/lib/esm/widgets/label-markup-native.ios.js +1 -0
  23. package/lib/esm/widgets/label-markup-native.js +1 -0
  24. package/lib/esm/widgets/label-markup.js +1 -1
  25. package/lib/esm/widgets/menu-slot.js +1 -0
  26. package/lib/esm/widgets/popup-menu-view.js +1 -1
  27. package/lib/esm/widgets/popup-menu.js +1 -1
  28. package/lib/esm/widgets/signals.js +1 -1
  29. package/lib/esm/widgets/single-child-base.js +1 -1
  30. package/lib/esm/widgets/single-child-cell.js +1 -1
  31. package/lib/types/entry-properties.spec.d.ts +1 -0
  32. package/lib/types/index.d.ts +4 -2
  33. package/lib/types/menu-model-door.spec.d.ts +1 -0
  34. package/lib/types/namespace/gio.d.ts +1 -1
  35. package/lib/types/template-xalign.spec.d.ts +2 -0
  36. package/lib/types/testing/ns-core.d.mts +11 -0
  37. package/lib/types/widgets/actions.d.ts +3 -3
  38. package/lib/types/widgets/adw-split-button.d.ts +17 -7
  39. package/lib/types/widgets/box-layout.d.ts +37 -0
  40. package/lib/types/widgets/gtk-box.d.ts +11 -5
  41. package/lib/types/widgets/gtk-entry.d.ts +62 -34
  42. package/lib/types/widgets/gtk-label.d.ts +24 -0
  43. package/lib/types/widgets/gtk-menu-button.d.ts +22 -13
  44. package/lib/types/widgets/gtk-popover-menu.d.ts +7 -7
  45. package/lib/types/widgets/index.d.ts +1 -2
  46. package/lib/types/widgets/label-markup-native.android.d.ts +5 -0
  47. package/lib/types/widgets/label-markup-native.d.ts +19 -0
  48. package/lib/types/widgets/label-markup-native.ios.d.ts +5 -0
  49. package/lib/types/widgets/label-markup.d.ts +62 -1
  50. package/lib/types/widgets/menu-slot.d.ts +40 -0
  51. package/lib/types/widgets/popup-menu-view.d.ts +3 -2
  52. package/lib/types/widgets/popup-menu.d.ts +8 -6
  53. package/lib/types/widgets/single-child-base.d.ts +3 -0
  54. package/lib/types/widgets/single-child-cell.d.ts +10 -5
  55. package/package.json +12 -12
  56. package/src/testing/ns-core.mts +19 -0
  57. package/src/theme/adwaita.css +24 -11
@@ -3,6 +3,23 @@ import { type LabelEllipsizeMode, type LabelJustification } from '@gjsify/adwait
3
3
  import { type ConstructProps } from './construct-props.js';
4
4
  /** Event name emitted when a link in the markup is tapped, before it is opened. */
5
5
  export declare const ACTIVATE_LINK = "activate-link";
6
+ /**
7
+ * `Gtk.Label:xalign` on a TEMPLATE CHILD — a plain `@nativescript/core` `Label` an Adw widget
8
+ * builds inside itself, standing in for a `<object class="GtkLabel">` in the upstream `.ui`.
9
+ *
10
+ * WHY IT EXISTS AND WHY IT IS NOT A NO-OP AT 0. The platform's own default is start-aligned, so
11
+ * `0` writes the word the view already had; the point is that the widget now STATES the alignment
12
+ * its upstream template states, instead of agreeing with it by accident. Upstream rows read
13
+ * left-aligned because `adw-action-row.ui` and its siblings each say `<property name="xalign">0`,
14
+ * not because GTK's default is 0 — it is 0.5 — and a port that leaves them implicit cannot be read
15
+ * against the `.ui` file that is its specification.
16
+ *
17
+ * START IS `'initial'`, NOT `'left'`: GTK's 0 is the START edge and mirrors in RTL, and `'initial'`
18
+ * is the platform's own direction-aware start. Only `0` and `0.5` are here, which is every value
19
+ * libadwaita's templates put on a label; `1` belongs to `adw-spin-row.ui`'s `GtkSpinButton`, an
20
+ * entry's `xalign` and not this one.
21
+ */
22
+ export declare function applyTemplateXalign(label: Label, xalign: 0 | 0.5): void;
6
23
  declare const GtkLabel_base: ((abstract new (...args: any[]) => {
7
24
  addEventListener(eventName: string, callback: (data: EventData) => void, thisArg?: unknown, once?: boolean): void;
8
25
  removeEventListener(eventName: string, callback?: (data: EventData) => void, thisArg?: unknown): void;
@@ -204,6 +221,13 @@ export declare class GtkLabel extends GtkLabel_base {
204
221
  set_css_classes(names: readonly string[]): void;
205
222
  private _setClasses;
206
223
  private _render;
224
+ /**
225
+ * `TextBase._setNativeText` — the one place every text write ends in, and therefore the
226
+ * seam the native markup path draws at. Refused by every host but Android, which then
227
+ * leaves the framework's own `formattedText`/`text` implementation in charge:
228
+ * `label-markup-native.ts`.
229
+ */
230
+ _setNativeText(reset?: boolean): void;
207
231
  /**
208
232
  * `emit_activate_link` for the link at `index`: the user's handlers under GTK's handled
209
233
  * accumulator, then — only if none handled it — the default launch.
@@ -1,4 +1,4 @@
1
- import type { AdwMenuActions, AdwMenuInput, AdwMenuModel } from '@gjsify/adwaita-core';
1
+ import type { AdwMenuActions, AdwMenuModel } from '@gjsify/adwaita-core';
2
2
  import type { EventData } from '@nativescript/core';
3
3
  import { AdwImageButton } from './adw-image-button.js';
4
4
  import { type ConstructProps } from './construct-props.js';
@@ -20,7 +20,13 @@ export interface MenuItemActivatedEventData extends EventData {
20
20
  }
21
21
  export declare class GtkMenuButton extends AdwImageButton {
22
22
  static readonly GTypeName: string;
23
- private _model;
23
+ /**
24
+ * `Gtk.MenuButton` has NO identity guard on `menu-model` — measured: every write
25
+ * notifies, including the same model twice and `null` over `null`
26
+ * (`MENU_MODEL_NOTIFY_VECTORS`), which is the opposite of what `Adw.SplitButton` next
27
+ * door does. So the notify below is unconditional, and the slot does not gate it.
28
+ */
29
+ private readonly _slot;
24
30
  private _actions;
25
31
  private _menuTitle;
26
32
  private _primary;
@@ -29,20 +35,23 @@ export declare class GtkMenuButton extends AdwImageButton {
29
35
  private _styleClasses;
30
36
  constructor(props?: ConstructProps<GtkMenuButton>);
31
37
  /**
32
- * The menu, normalised (ADR 0042) — opened as an Android `PopupMenu` on tap.
38
+ * The menu — a real `Gio.MenuModel` since ADR 0128 — opened as an Android `PopupMenu`
39
+ * on tap. `null` is the one spelling of "no menu".
33
40
  *
34
- * Accepts every input form the portable model does, a bare `string[]` included —
35
- * but NOT a JSON string; see `AdwSplitButton.menuModel` for why the XML door stays
36
- * shut until a probe can prove it, and why being shut is not the same as being
37
- * silent.
41
+ * IT TAKES A MODEL AND NOTHING ELSE: `Gio.Menu` from this package's `Gio` namespace, or
42
+ * `buildMenu([…])` for the authored shorthands (a bare `string[]` included). An array
43
+ * written straight here is refused by the GObject value check, word for word as GJS
44
+ * refuses it. A JSON STRING is refused too, with its own message — see
45
+ * `AdwSplitButton.menuModel` for why the XML door stays shut until a probe can prove
46
+ * it, and why being shut is not the same as being silent.
38
47
  */
39
- get menuModel(): AdwMenuModel;
40
- set menuModel(value: AdwMenuInput);
48
+ get menuModel(): AdwMenuModel | null;
49
+ set menuModel(value: AdwMenuModel | null);
41
50
  /** `Gtk.MenuButton:menu-model` — the GIR spelling of {@link menuModel}. */
42
- get menu_model(): AdwMenuModel;
43
- set menu_model(value: AdwMenuInput);
44
- get_menu_model(): AdwMenuModel;
45
- set_menu_model(value: AdwMenuInput): void;
51
+ get menu_model(): AdwMenuModel | null;
52
+ set menu_model(value: AdwMenuModel | null);
53
+ get_menu_model(): AdwMenuModel | null;
54
+ set_menu_model(value: AdwMenuModel | null): void;
46
55
  /**
47
56
  * What the action group publishes about the actions this menu names — the portable
48
57
  * stand-in for a `GActionGroup`. Left `null`, the registry above the button answers
@@ -1,5 +1,5 @@
1
1
  import { Observable, type EventData } from '@nativescript/core';
2
- import type { AdwMenuActions, AdwMenuInput, AdwMenuModel } from '@gjsify/adwaita-core';
2
+ import type { AdwMenuActions, AdwMenuModel } from '@gjsify/adwaita-core';
3
3
  import type { ActionHost } from './actions.js';
4
4
  import { type ConstructProps } from './construct-props.js';
5
5
  /** `GtkPopover::closed`, emitted when the menu goes away. */
@@ -71,16 +71,16 @@ declare const GtkPopoverMenu_base: ((abstract new (...args: any[]) => {
71
71
  }) & typeof Observable;
72
72
  export declare class GtkPopoverMenu extends GtkPopoverMenu_base {
73
73
  static readonly GTypeName: string;
74
- private _model;
74
+ private readonly _slot;
75
75
  private _actions;
76
76
  private _parent;
77
77
  private _open;
78
78
  constructor(props?: ConstructProps<GtkPopoverMenu>);
79
- /** `Gtk.PopoverMenu:menu-model`. */
80
- get menuModel(): AdwMenuModel;
81
- set menuModel(value: AdwMenuInput);
82
- set_menu_model(model: AdwMenuInput | null): void;
83
- get_menu_model(): AdwMenuModel;
79
+ /** `Gtk.PopoverMenu:menu-model` — a real `Gio.MenuModel`, or `null` (ADR 0128). */
80
+ get menuModel(): AdwMenuModel | null;
81
+ set menuModel(value: AdwMenuModel | null);
82
+ set_menu_model(model: AdwMenuModel | null): void;
83
+ get_menu_model(): AdwMenuModel | null;
84
84
  /** What the action group publishes about the actions this menu names; see `GtkMenuButton.actions`. */
85
85
  get actions(): AdwMenuActions | null;
86
86
  set actions(value: AdwMenuActions | null);
@@ -4,8 +4,7 @@ export { AdwActionRow } from './adw-action-row.js';
4
4
  export { AdwSwitchRow, NOTIFY_ACTIVE } from './adw-switch-row.js';
5
5
  export { AdwEntryRow, NOTIFY_TEXT, NOTIFY_TEXT_LENGTH, NOTIFY_MAX_LENGTH, NOTIFY_EDITABLE, NOTIFY_SHOW_APPLY_BUTTON, NOTIFY_ACTIVATES_DEFAULT, SIGNAL_APPLY, SIGNAL_ENTRY_ACTIVATED, } from './adw-entry-row.js';
6
6
  export { AdwPasswordEntryRow } from './adw-password-entry-row.js';
7
- export { GtkEntry, ACTIVATE as ENTRY_ACTIVATE, NOTIFY_TEXT as NOTIFY_ENTRY_TEXT } from './gtk-entry.js';
8
- export type { NotifyEntryTextEventData } from './gtk-entry.js';
7
+ export { GtkEntry, ACTIVATE as ENTRY_ACTIVATE, CHANGED as ENTRY_CHANGED, NOTIFY_TEXT as NOTIFY_ENTRY_TEXT, NOTIFY_TEXT_LENGTH as NOTIFY_ENTRY_TEXT_LENGTH, NOTIFY_MAX_LENGTH as NOTIFY_ENTRY_MAX_LENGTH, NOTIFY_PLACEHOLDER_TEXT, NOTIFY_EDITABLE as NOTIFY_ENTRY_EDITABLE, } from './gtk-entry.js';
9
8
  export { AdwComboRow, ComboState, NOTIFY_SELECTED } from './adw-combo-row.js';
10
9
  export type { AdwComboOption, ComboStateChange, ComboStateListener } from './adw-combo-row.js';
11
10
  export { GtkDropDown, NOTIFY_SELECTED as NOTIFY_DROP_DOWN_SELECTED } from './gtk-drop-down.js';
@@ -0,0 +1,5 @@
1
+ import { type LabelMarkupNativeText } from './label-markup.js';
2
+ /** Rationale and contract: `label-markup-native.ts`. */
3
+ export declare function labelMarkupHoldNative(label: object, text: LabelMarkupNativeText | null): boolean;
4
+ /** Rationale and contract: `label-markup-native.ts`. */
5
+ export declare function labelMarkupDrawNative(label: object, reset: boolean): boolean;
@@ -0,0 +1,19 @@
1
+ import type { LabelMarkupNativeText } from './label-markup.js';
2
+ /**
3
+ * Record the markup `label` must draw natively, or clear it with `null` — answers whether
4
+ * this host draws its own styled text at all, so a caller can take the `FormattedString`
5
+ * path on the same condition it would take it on.
6
+ *
7
+ * A host that answers `true` here MUST answer `true` from {@link labelMarkupDrawNative}
8
+ * for as long as something is held, and the caller may rely on that: nothing re-reads the
9
+ * markup between the hold and the write.
10
+ */
11
+ export declare function labelMarkupHoldNative(_label: object, _text: LabelMarkupNativeText | null): boolean;
12
+ /**
13
+ * Draw the held markup into `label`'s native text view — `false` when there is nothing held
14
+ * or this host has no such text, and then the caller lets `TextBase._setNativeText` run.
15
+ *
16
+ * `reset` is the platform's own "clear the text" call, which no styled text can answer:
17
+ * it is always refused so the base implementation clears the view.
18
+ */
19
+ export declare function labelMarkupDrawNative(_label: object, _reset: boolean): boolean;
@@ -0,0 +1,5 @@
1
+ import type { LabelMarkupNativeText } from './label-markup.js';
2
+ /** Record what `label` must draw natively — iOS draws none. See {@link labelMarkupHoldNative}. */
3
+ export declare function labelMarkupHoldNative(_label: object, _text: LabelMarkupNativeText | null): boolean;
4
+ /** Draw the held markup — iOS holds none. See {@link labelMarkupDrawNative}. */
5
+ export declare function labelMarkupDrawNative(_label: object, _reset: boolean): boolean;
@@ -1,5 +1,66 @@
1
1
  import { FormattedString, Span } from '@nativescript/core';
2
- import { type LabelMarkupRender, type LabelMarkupRun } from '@gjsify/adwaita-core';
2
+ import { type LabelMarkupRender, type LabelMarkupRun, type LabelMarkupStyle } from '@gjsify/adwaita-core';
3
+ /**
4
+ * The native FACE one run asks for: the typeface, the two lines, the baseline and the font
5
+ * factor, with pango's tags and `<span>` attributes already resolved against each other.
6
+ *
7
+ * WHY A SECOND SHAPE BESIDE {@link labelMarkupSpan}. A `Span` IS the shape on the surfaces
8
+ * that go through a `FormattedString`, so there the resolution and the write are one
9
+ * function. Android's spans are not a shape at all — `TypefaceSpan`, `StyleSpan`,
10
+ * `UnderlineSpan`, `RelativeSizeSpan` are independent objects over a RANGE of one
11
+ * builder — so the decisions have to be readable before anything native exists, which is
12
+ * also what makes them assertable off a device. `label-markup-native.android.ts` turns one
13
+ * face into those spans and decides nothing else.
14
+ *
15
+ * THE SCALE IS RELATIVE, which is what pango's is. `<big>` is a FACTOR
16
+ * (`PANGO_SCALE_LARGE`), so a platform with a relative span needs no base size and drops
17
+ * nothing — where the `Span` path's `fontSize` is an absolute number of DIPs and has to
18
+ * resolve the factor against a size something has written, which is why it SKIPS the scale
19
+ * when nothing has (see the header). The same markup is therefore more faithful on the
20
+ * native path, not differently faithful; the measured corpus has no `<big>`/`<small>` at
21
+ * all, so no label in it renders differently either way.
22
+ *
23
+ * THE WEIGHT LADDER COLLAPSES TO BOLD, declared rather than approximated: Android picks a
24
+ * weight with `Typeface.create(family, weight, italic)` from API 28 and has nothing but
25
+ * `Typeface.BOLD` below it, and this port supports API 24. So pango's named and numeric
26
+ * weights are read and answered as bold from {@link BOLD_FROM} up. `semilight`, `book` and
27
+ * `ultraheavy` are dropped, which is the same answer {@link SPAN_WEIGHTS} gives them.
28
+ */
29
+ export interface LabelMarkupFace {
30
+ /** The typeface family, or `undefined` for the view's own. `<tt>` is `monospace`. */
31
+ readonly family: string | undefined;
32
+ readonly bold: boolean;
33
+ readonly italic: boolean;
34
+ readonly underline: boolean;
35
+ readonly strikethrough: boolean;
36
+ /** `<sub>` / `<sup>` — a baseline shift, not a size. */
37
+ readonly script: 'sub' | 'sup' | null;
38
+ /** The font factor `<big>`, `<small>`, `<sub>` and `<sup>` multiply up to. 1 means none. */
39
+ readonly scale: number;
40
+ }
41
+ /**
42
+ * One run's style as the face a native span-setter writes.
43
+ *
44
+ * The `<span>` attributes are read OUTERMOST FIRST and the pango tags after, so a tag wins
45
+ * a collision — the same declared order {@link labelMarkupSpan} applies, for the same
46
+ * reason: the runs record the tags as booleans and the `<span>`s as a separate stack, so
47
+ * neither renderer can know which element was inner.
48
+ */
49
+ export declare function labelMarkupFace(style: LabelMarkupStyle, link: boolean): LabelMarkupFace;
50
+ /**
51
+ * A label's markup as the platform half of this package has to DRAW it — everything
52
+ * `label-markup-native.ts` needs and nothing a `FormattedString` would add.
53
+ *
54
+ * `onLinkTap` rather than the links themselves: following a link is the widget's decision
55
+ * (`GtkLabel._activateLink` runs `::activate-link` under GTK's handled accumulator), and a
56
+ * span-setter that reached for `render.links[i].href` would be making it a second time.
57
+ */
58
+ export interface LabelMarkupNativeText {
59
+ readonly render: LabelMarkupRender;
60
+ /** `use-underline` — whether the mnemonic marker is stripped out of each run's text. */
61
+ readonly mnemonics: boolean;
62
+ onLinkTap(index: number): void;
63
+ }
3
64
  /**
4
65
  * One run as one `Span`.
5
66
  *
@@ -0,0 +1,40 @@
1
+ import type { AdwMenuTree, GioMenuModel } from '@gjsify/adwaita-core';
2
+ export declare class MenuSlot {
3
+ private readonly widget;
4
+ private readonly onItemsChanged;
5
+ private readonly _authored;
6
+ private _model;
7
+ private _tree;
8
+ private _unwatch;
9
+ /**
10
+ * @param widget the class name {@link refuseMenuString} names in its refusal.
11
+ * @param onItemsChanged what to do when the HELD menu mutates under the widget.
12
+ */
13
+ constructor(widget: string, onItemsChanged: () => void);
14
+ /** The model itself, by identity — what `menuModel` answers. */
15
+ get model(): GioMenuModel | null;
16
+ /** The snapshot `planPopupMenu` reads. Re-taken on each `items-changed`, never aliased. */
17
+ get tree(): AdwMenuTree;
18
+ /**
19
+ * Whether there is anything to show — NOT whether there is a menu.
20
+ *
21
+ * `null` and an empty `Gio.Menu` are different menus, and on GTK they behave
22
+ * differently: an empty non-null model still builds a `GtkPopoverMenu` (measured,
23
+ * `MENU_MODEL_DOOR_VECTORS`). A `PopupMenu` with no items draws no window at all, so
24
+ * this is the question the TAP asks, and the widgets ask `model === null` where GTK asks
25
+ * about the model.
26
+ */
27
+ get isEmpty(): boolean;
28
+ /**
29
+ * A property write: a real model by identity, `null` for no menu — and a `TypeError` for
30
+ * a string, an array or anything else, which this door does not take (`buildMenu` is how
31
+ * an array becomes a model now).
32
+ *
33
+ * The refusal is a THROW because a property assignment is a call: whoever wrote the
34
+ * menu is on the stack and can hear it. There is no second, quieter door here the way
35
+ * the browser has one for markup.
36
+ */
37
+ write(value: unknown): void;
38
+ /** Hold `next`, snapshot it, and listen to it — the three that always happen together. */
39
+ private _adopt;
40
+ }
@@ -1,8 +1,9 @@
1
- import type { AdwMenuActions, AdwMenuItem, AdwMenuModel, AdwMenuPath } from '@gjsify/adwaita-core';
1
+ import type { AdwMenuActions, AdwMenuItem, AdwMenuPath, AdwMenuTree } from '@gjsify/adwaita-core';
2
2
  import { type ActionHost } from './actions.js';
3
3
  import { type PopupMenuSurface } from './popup-menu.js';
4
4
  export interface MenuPopupOptions {
5
- readonly model: AdwMenuModel;
5
+ /** The SNAPSHOT of the menu model, as `MenuSlot.tree` holds it (ADR 0128 § 3). */
6
+ readonly tree: AdwMenuTree;
6
7
  /** What the application wrote itself; absent, the registry above `anchor` answers. */
7
8
  readonly actions?: AdwMenuActions | null;
8
9
  /** A leaf item was chosen, after its action fired. */
@@ -1,4 +1,4 @@
1
- import type { AdwMenuActions, AdwMenuModel, AdwMenuPath, PopupMenuLevelPlan, PopupMenuPlan } from '@gjsify/adwaita-core';
1
+ import type { AdwMenuActions, AdwMenuPath, AdwMenuTree, PopupMenuLevelPlan, PopupMenuPlan } from '@gjsify/adwaita-core';
2
2
  /** The `MenuItem` calls the driver makes. */
3
3
  export interface PopupMenuItemLike {
4
4
  setEnabled(enabled: boolean): unknown;
@@ -33,7 +33,8 @@ export declare const GROUP_DIVIDER_API = 28;
33
33
  export declare function fillPopupMenu(menu: PopupMenuLike, level: PopupMenuLevelPlan, apiLevel: number): Map<number, AdwMenuPath>;
34
34
  export interface OpenPopupMenuOptions {
35
35
  readonly surface: PopupMenuSurface;
36
- readonly model: AdwMenuModel;
36
+ /** The SNAPSHOT of the menu model, as `MenuSlot.tree` holds it (ADR 0128 § 3). */
37
+ readonly tree: AdwMenuTree;
37
38
  /** What {@link resolveMenuItemState} reads; from `menuActionsFor` it is the registry's. */
38
39
  readonly actions?: AdwMenuActions;
39
40
  /** A tap on a leaf item, with its model path. Fire the action here (`activateMenuItem`). */
@@ -46,14 +47,15 @@ export interface OpenPopupMenuOptions {
46
47
  */
47
48
  export declare function openPopupMenu(options: OpenPopupMenuOptions): PopupMenuPlan;
48
49
  /**
49
- * Throw if `model` holds what `PopupMenu` can never draw, at the ASSIGNMENT: a `custom` item or a
50
+ * Throw if `tree` holds what `PopupMenu` can never draw, at the ASSIGNMENT: a `custom` item or a
50
51
  * section label. A radio run that shares a group needs the actions to be known, so it throws when
51
52
  * the menu is opened.
52
53
  */
53
- export declare function assertPopupMenuAssignable(model: AdwMenuModel): void;
54
+ export declare function assertPopupMenuAssignable(tree: AdwMenuTree): void;
54
55
  /**
55
56
  * A JSON string is not a menu model here: NativeScript's XML Builder writes an attribute straight
56
- * onto the property, so accepting one would open an XML door nothing can prove, and
57
- * `normalizeMenuModel` would turn it into an EMPTY menu with nothing saying why.
57
+ * onto the property, so accepting one would open an XML door nothing can prove. Since ADR 0128
58
+ * the core's door DOES parse one — that is how the browser's `menu-model` attribute works — so
59
+ * this stays in front of it rather than relying on a refusal the shared door no longer makes.
58
60
  */
59
61
  export declare function refuseMenuString(value: unknown, widget: string): void;
@@ -4,10 +4,13 @@ export declare abstract class AdwSingleChildBase extends AdwStyledLayoutBase {
4
4
  private _child;
5
5
  constructor();
6
6
  private _columnIsStar;
7
+ private _rowIsStar;
7
8
  onLoaded(): void;
8
9
  onUnloaded(): void;
9
10
  private _onWidthChangeSyncColumn;
11
+ private _onHeightChangeSyncRow;
10
12
  private _syncColumnToAlignment;
13
+ private _syncRowToAlignment;
11
14
  /** The child, or `null`. */
12
15
  get child(): View | null;
13
16
  set child(view: View | null);
@@ -1,8 +1,13 @@
1
1
  /**
2
- * Whether the single cell of a one-child container is `star` rather than `auto`.
2
+ * Whether the single cell of a one-child container is `star` rather than `auto`, on ONE axis.
3
3
  *
4
- * `star` when the container's width is settled — either because it stretches to its parent,
5
- * or because a definite `width` was written on it. `auto` otherwise, so the container can
6
- * still report its child's natural width and be placed by its alignment.
4
+ * `star` when the container's extent along that axis is settled — either because it stretches
5
+ * to its parent, or because a definite `width` / `height` was written on it. `auto` otherwise,
6
+ * so the container can still report its child's natural size and be placed by its alignment.
7
+ *
8
+ * TAKES NO AXIS, because there is nothing axis-specific left once the question is phrased that
9
+ * way: `'stretch'` is the stretching value of BOTH `horizontalAlignment` and
10
+ * `verticalAlignment`, and a settled `width` reads exactly like a settled `height`. The column
11
+ * passes `horizontalAlignment` + `width`, the row `verticalAlignment` + `height`.
7
12
  */
8
- export declare function singleChildCellIsStar(horizontalAlignment: unknown, width: unknown): boolean;
13
+ export declare function singleChildCellIsStar(alignment: unknown, length: unknown): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-nativescript",
3
- "version": "0.64.13",
3
+ "version": "0.64.14",
4
4
  "description": "Native Adwaita widgets for the NativeScript runtime — real NativeScript components (StackLayout/GridLayout/Switch/Label) styled like Libadwaita, not a webview",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -73,15 +73,15 @@
73
73
  "design-system"
74
74
  ],
75
75
  "dependencies": {
76
- "@gjsify/adwaita-core": "^0.64.13",
77
- "@gjsify/adwaita-fonts": "^0.64.13",
78
- "@gjsify/adwaita-icons": "^0.64.13",
79
- "@gjsify/canvas2d-core": "^0.64.13",
80
- "@gjsify/native-platform": "^0.64.13"
76
+ "@gjsify/adwaita-core": "^0.64.14",
77
+ "@gjsify/adwaita-fonts": "^0.64.14",
78
+ "@gjsify/adwaita-icons": "^0.64.14",
79
+ "@gjsify/canvas2d-core": "^0.64.14",
80
+ "@gjsify/native-platform": "^0.64.14"
81
81
  },
82
82
  "peerDependencies": {
83
83
  "@nativescript/core": "*",
84
- "@gjsify/app-settings": "^0.64.13"
84
+ "@gjsify/app-settings": "^0.64.14"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "@nativescript/core": {
@@ -92,11 +92,11 @@
92
92
  }
93
93
  },
94
94
  "devDependencies": {
95
- "@gjsify/app-settings": "^0.64.13",
96
- "@gjsify/blueprint": "^0.64.13",
97
- "@gjsify/cli": "^0.64.13",
98
- "@gjsify/unit": "^0.64.13",
99
- "@gjsify/vite-plugin-blueprint": "^0.64.13",
95
+ "@gjsify/app-settings": "^0.64.14",
96
+ "@gjsify/blueprint": "^0.64.14",
97
+ "@gjsify/cli": "^0.64.14",
98
+ "@gjsify/unit": "^0.64.14",
99
+ "@gjsify/vite-plugin-blueprint": "^0.64.14",
100
100
  "@types/node": "^25.9.2",
101
101
  "typescript": "^6.0.3"
102
102
  },
@@ -667,11 +667,22 @@ export class GridLayout extends LayoutBase {
667
667
  if (at !== -1) this._rows.splice(at, 1);
668
668
  }
669
669
 
670
+ /** `GridLayoutBase.removeColumn` — BY SPEC, like `removeRow`, not by index. */
671
+ removeColumn(itemSpec: ItemSpec): void {
672
+ const at = this._cols.indexOf(itemSpec);
673
+ if (at !== -1) this._cols.splice(at, 1);
674
+ }
675
+
670
676
  /** `GridLayoutBase.getColumns` — a copy, as on a device. */
671
677
  getColumns(): ItemSpec[] {
672
678
  return [...this._cols];
673
679
  }
674
680
 
681
+ /** `GridLayoutBase.getRows` — the same read on the other axis. */
682
+ getRows(): ItemSpec[] {
683
+ return [...this._rows];
684
+ }
685
+
675
686
  removeColumns(): void {
676
687
  this._cols.length = 0;
677
688
  }
@@ -893,6 +904,14 @@ export class Label extends View {
893
904
  this._text = value?.toString() ?? '';
894
905
  }
895
906
 
907
+ /**
908
+ * `TextBase._setNativeText` — the framework's sink for every text write, and the seam
909
+ * the native markup path draws at (`widgets/label-markup-native.ts`). There is no
910
+ * native text view off a device, so this records nothing: it exists because the port
911
+ * overrides it and `super._setNativeText()` has to be callable.
912
+ */
913
+ _setNativeText(_reset = false): void {}
914
+
896
915
  textWrap = false;
897
916
  textAlignment = 'initial';
898
917
  textOverflow = 'initial';
@@ -506,13 +506,22 @@ Page.adw-window {
506
506
 
507
507
  /* ===== Button (variants) ===== */
508
508
 
509
+ /* A FLOOR AND NOT A BOX. 38 is libadwaita's `min-height: 24px` plus its 5px of vertical
510
+ * padding twice (_buttons.scss, pin 42f647ff) — a MINIMUM there, and GTK has no CSS
511
+ * `height` at all. Writing it as NativeScript's `height`, which is exact, made every
512
+ * button in the port exactly 38 tall and silently swallowed `height-request`, which the
513
+ * bridge maps to `minHeight` and which GTK treats as a second floor: Learn6502's d-pad
514
+ * asks each of its five cells for 50×50 and got 50×38, so the cross came out as a row of
515
+ * flattened buttons. `min-height` is the property that means what the SCSS means, it
516
+ * composes with `height-request` the way GTK composes its two floors — the larger wins —
517
+ * and a caller that really wants an exact box can still write `height` itself. */
509
518
  .adw-button {
510
519
  background-color: rgba(0, 0, 0, 0.08);
511
520
  color: rgba(0, 0, 0, 0.8);
512
521
  border-radius: 9;
513
522
  font-weight: 700;
514
523
  padding: 5 16 5 16;
515
- height: 38;
524
+ min-height: 38;
516
525
  }
517
526
 
518
527
  .adw-button.suggested-action {
@@ -534,10 +543,10 @@ Page.adw-window {
534
543
  * pin 42f647ff). The padding is the whole variant, and it is why this rule HAS to
535
544
  * restate the height.
536
545
  *
537
- * `.adw-button` above pins `height: 38`, and a NativeScript `height` is an EXACT box
538
- * where GTK's `min-height` is a floor — the same non-equivalence ADR 0034 measured for
539
- * `adw-spinner.size`. So a variant that doubles the vertical padding cannot grow the
540
- * box it sits in: the base budgets 38 − (5 + 5) = 28 for the label, and this one left
546
+ * `.adw-button` above pins a 38 floor, and this variant doubles the vertical padding
547
+ * inside it. While that floor was written as an EXACT NativeScript `height` — the
548
+ * non-equivalence ADR 0034 measured for `adw-spinner.size` — the variant could not grow
549
+ * the box it sat in: the base budgets 38 − (5 + 5) = 28 for the label, and this one left
541
550
  * 38 − (10 + 10) = 18 for a `.adw-button-label` at `font-size: 15`, whose line box does
542
551
  * not fit in 18. The pill was clipped, and every consumer that wanted one had to
543
552
  * override the height itself — which is how the defect surfaced, in Learn6502.
@@ -547,13 +556,17 @@ Page.adw-window {
547
556
  * 34, + 10px twice is 44 — so the pill is taller than the plain button there too.
548
557
  *
549
558
  * THE RULE THIS VARIANT BROKE, stated because the next variant will meet it: in this
550
- * stylesheet a class that changes vertical padding on a widget whose base pins an exact
551
- * `height` must restate that height. `.adw-button.circular` does (34), and both split
552
- * button halves do (38) beside their own padding. This one did not, and nothing said so. */
559
+ * stylesheet a class that changes vertical padding on a widget whose base states a
560
+ * `min-height` must restate that floor at its own padding. `.adw-button.circular` does
561
+ * (34), and both split button halves do (38) beside their own padding. This one did not,
562
+ * and nothing said so. The floors are `min-*` rather than `height` / `width` since the
563
+ * d-pad incident above, so a `height-request` larger than the floor now wins as it does
564
+ * in GTK — but a floor that is too SMALL for its own padding still clips, which is the
565
+ * half this comment is about and the reason the number is restated here. */
553
566
  .adw-button.pill {
554
567
  border-radius: 9999;
555
568
  padding: 10 32 10 32;
556
- height: 48;
569
+ min-height: 48;
557
570
  }
558
571
 
559
572
  /* `%circular_button` — the explicit exception to the 9px rounded square: a full
@@ -563,8 +576,8 @@ Page.adw-window {
563
576
  * at all", and a class with no rule would have drawn a rounded rectangle instead. The
564
577
  * 34 is the same number `.adw-image-button` above carries, from the same line. */
565
578
  .adw-button.circular {
566
- width: 34;
567
- height: 34;
579
+ min-width: 34;
580
+ min-height: 34;
568
581
  border-radius: 9999;
569
582
  padding: 0;
570
583
  }