@gtkx/react 0.13.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/jsx.d.ts CHANGED
@@ -2,7 +2,7 @@ import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { ReactElement, ReactNode } from "react";
3
3
  import type { RenderItemFn } from "./nodes/internal/list-item-renderer.js";
4
4
  import type { TreeRenderItemFn } from "./nodes/internal/tree-list-item-renderer.js";
5
- export type { EventControllerProps } from "./types.js";
5
+ export type { DragSourceProps, DropTargetProps, EventControllerProps } from "./types.js";
6
6
  /**
7
7
  * Props for slot-based child positioning.
8
8
  *
@@ -14,6 +14,13 @@ export type SlotProps = {
14
14
  /** Content to place in the slot */
15
15
  children?: ReactNode;
16
16
  };
17
+ /**
18
+ * Props for virtual child containers that don't expose slot id.
19
+ */
20
+ export type VirtualSlotProps = {
21
+ /** Content to place in the slot */
22
+ children?: ReactNode;
23
+ };
17
24
  /**
18
25
  * Props for items in a {@link ListView} or {@link GridView}.
19
26
  *
@@ -60,7 +67,7 @@ export type StringListItemProps = {
60
67
  *
61
68
  * @see {@link GridChild} for usage
62
69
  */
63
- export type GridChildProps = Omit<SlotProps, "id"> & {
70
+ export type GridChildProps = VirtualSlotProps & {
64
71
  /** Column index (0-based) */
65
72
  column?: number;
66
73
  /** Row index (0-based) */
@@ -75,7 +82,7 @@ export type GridChildProps = Omit<SlotProps, "id"> & {
75
82
  *
76
83
  * @see {@link FixedChild} for usage
77
84
  */
78
- export type FixedChildProps = Omit<SlotProps, "id"> & {
85
+ export type FixedChildProps = VirtualSlotProps & {
79
86
  /** X coordinate in pixels */
80
87
  x?: number;
81
88
  /** Y coordinate in pixels */
@@ -131,18 +138,18 @@ export type ColumnViewRootProps<C extends string = string> = {
131
138
  /**
132
139
  * Props for notebook (tabbed) pages.
133
140
  */
134
- export type NotebookPageProps = Omit<SlotProps, "id"> & {
141
+ export type NotebookPageProps = VirtualSlotProps & {
135
142
  /** Tab label text (optional when using Notebook.PageTab) */
136
143
  label?: string;
137
144
  };
138
145
  /**
139
146
  * Props for custom notebook page tab widgets.
140
147
  */
141
- export type NotebookPageTabProps = SlotProps;
148
+ export type NotebookPageTabProps = VirtualSlotProps;
142
149
  /**
143
150
  * Props for the root Stack component.
144
151
  */
145
- export type StackRootProps = Omit<SlotProps, "id"> & {
152
+ export type StackRootProps = VirtualSlotProps & {
146
153
  /** ID of the currently visible page */
147
154
  page?: string;
148
155
  };
@@ -151,7 +158,7 @@ export type StackRootProps = Omit<SlotProps, "id"> & {
151
158
  *
152
159
  * @see {@link StackPage} for usage
153
160
  */
154
- export type StackPageProps = Omit<SlotProps, "id"> & {
161
+ export type StackPageProps = VirtualSlotProps & {
155
162
  /** Unique identifier for this page (used with page prop) */
156
163
  id?: string;
157
164
  /** Display title shown in stack switchers */
@@ -205,7 +212,7 @@ export type MenuSubmenuProps = {
205
212
  /**
206
213
  * Props for children within an Overlay container.
207
214
  */
208
- export type OverlayChildProps = Omit<SlotProps, "id"> & {
215
+ export type OverlayChildProps = VirtualSlotProps & {
209
216
  /** Whether to include this child in size measurement */
210
217
  measure?: boolean;
211
218
  /** Whether to clip this overlay child to the main child bounds */
@@ -307,33 +314,45 @@ export type ExpanderRowChildProps = {
307
314
  /** Children to add to this slot */
308
315
  children?: ReactNode;
309
316
  };
317
+ type NavigationPageBaseProps = {
318
+ title?: string;
319
+ canPop?: boolean;
320
+ children?: ReactNode;
321
+ };
310
322
  /**
311
- * Props for the NavigationPage virtual element.
323
+ * Props for the NavigationPage virtual element with type-safe targeting.
312
324
  *
313
- * Used to declaratively define pages in an AdwNavigationView.
325
+ * The `for` prop is required and determines valid `id` values:
326
+ * - `AdwNavigationView`: `id` can be any string (page tags for navigation history)
327
+ * - `AdwNavigationSplitView`: `id` is narrowed to `"content" | "sidebar"` (slot positions)
314
328
  *
315
329
  * @example
316
330
  * ```tsx
331
+ * // In NavigationView - id can be any string
317
332
  * <AdwNavigationView history={["home", "details"]}>
318
- * <x.NavigationPage id="home" title="Home">
333
+ * <x.NavigationPage for={AdwNavigationView} id="home" title="Home">
319
334
  * <HomeContent />
320
335
  * </x.NavigationPage>
321
- * <x.NavigationPage id="details" title="Details">
322
- * <DetailsContent />
323
- * </x.NavigationPage>
324
336
  * </AdwNavigationView>
337
+ *
338
+ * // In NavigationSplitView - id is narrowed to "content" | "sidebar"
339
+ * <AdwNavigationSplitView>
340
+ * <x.NavigationPage for={AdwNavigationSplitView} id="sidebar" title="Sidebar">
341
+ * <SidebarContent />
342
+ * </x.NavigationPage>
343
+ * <x.NavigationPage for={AdwNavigationSplitView} id="content" title="Content">
344
+ * <MainContent />
345
+ * </x.NavigationPage>
346
+ * </AdwNavigationSplitView>
325
347
  * ```
326
348
  */
327
- export type NavigationPageProps = {
328
- /** Unique identifier for this page (used in history array) */
349
+ export type NavigationPageProps = (NavigationPageBaseProps & {
350
+ for: "AdwNavigationView";
329
351
  id: string;
330
- /** Title displayed in the header bar */
331
- title?: string;
332
- /** Whether the page can be popped via back button/gestures */
333
- canPop?: boolean;
334
- /** Page content */
335
- children?: ReactNode;
336
- };
352
+ }) | (NavigationPageBaseProps & {
353
+ for: "AdwNavigationSplitView";
354
+ id: import("./generated/jsx.js").WidgetSlotNames["AdwNavigationSplitView"];
355
+ });
337
356
  /**
338
357
  * Type mapping widget names to their available slot IDs.
339
358
  */
@@ -772,18 +791,30 @@ export declare const x: {
772
791
  */
773
792
  ExpanderRowAction: "ExpanderRowAction";
774
793
  /**
775
- * A page within an AdwNavigationView.
794
+ * Type-safe page component for AdwNavigationView or AdwNavigationSplitView.
795
+ *
796
+ * The `for` prop is required and determines valid `id` values:
797
+ * - `AdwNavigationView`: any string (page tags for navigation history)
798
+ * - `AdwNavigationSplitView`: `"content"` or `"sidebar"` (slot positions)
776
799
  *
777
800
  * @example
778
801
  * ```tsx
802
+ * // In NavigationView - id can be any string
779
803
  * <AdwNavigationView history={["home"]}>
780
- * <x.NavigationPage id="home" title="Home">
804
+ * <x.NavigationPage for={AdwNavigationView} id="home" title="Home">
781
805
  * <GtkLabel label="Welcome!" />
782
806
  * </x.NavigationPage>
783
- * <x.NavigationPage id="settings" title="Settings">
784
- * <GtkLabel label="Settings page" />
785
- * </x.NavigationPage>
786
807
  * </AdwNavigationView>
808
+ *
809
+ * // In NavigationSplitView - id is narrowed to "content" | "sidebar"
810
+ * <AdwNavigationSplitView>
811
+ * <x.NavigationPage for={AdwNavigationSplitView} id="sidebar" title="Sidebar">
812
+ * <GtkLabel label="Sidebar" />
813
+ * </x.NavigationPage>
814
+ * <x.NavigationPage for={AdwNavigationSplitView} id="content" title="Content">
815
+ * <GtkLabel label="Content" />
816
+ * </x.NavigationPage>
817
+ * </AdwNavigationSplitView>
787
818
  * ```
788
819
  */
789
820
  NavigationPage: "NavigationPage";
@@ -792,8 +823,8 @@ declare global {
792
823
  namespace React {
793
824
  namespace JSX {
794
825
  interface IntrinsicElements {
795
- ActionRowPrefix: SlotProps;
796
- ActionRowSuffix: SlotProps;
826
+ ActionRowPrefix: VirtualSlotProps;
827
+ ActionRowSuffix: VirtualSlotProps;
797
828
  CalendarMark: CalendarMarkProps;
798
829
  ColumnViewColumn: ColumnViewColumnProps<any>;
799
830
  ExpanderRowAction: ExpanderRowChildProps;
@@ -806,16 +837,16 @@ declare global {
806
837
  MenuSection: MenuSectionProps;
807
838
  MenuSubmenu: MenuSubmenuProps;
808
839
  NotebookPage: NotebookPageProps;
809
- NotebookPageTab: NotebookPageTabProps;
840
+ NotebookPageTab: VirtualSlotProps;
810
841
  OverlayChild: OverlayChildProps;
811
- PackEnd: SlotProps;
812
- PackStart: SlotProps;
842
+ PackEnd: VirtualSlotProps;
843
+ PackStart: VirtualSlotProps;
813
844
  ScaleMark: ScaleMarkProps;
814
845
  SimpleListItem: StringListItemProps;
815
846
  StackPage: StackPageProps;
816
847
  Toggle: ToggleProps;
817
- ToolbarBottom: SlotProps;
818
- ToolbarTop: SlotProps;
848
+ ToolbarBottom: VirtualSlotProps;
849
+ ToolbarTop: VirtualSlotProps;
819
850
  TreeListItem: TreeListItemProps<any>;
820
851
  NavigationPage: NavigationPageProps;
821
852
  }
package/dist/jsx.js CHANGED
@@ -398,18 +398,30 @@ export const x = {
398
398
  */
399
399
  ExpanderRowAction: "ExpanderRowAction",
400
400
  /**
401
- * A page within an AdwNavigationView.
401
+ * Type-safe page component for AdwNavigationView or AdwNavigationSplitView.
402
+ *
403
+ * The `for` prop is required and determines valid `id` values:
404
+ * - `AdwNavigationView`: any string (page tags for navigation history)
405
+ * - `AdwNavigationSplitView`: `"content"` or `"sidebar"` (slot positions)
402
406
  *
403
407
  * @example
404
408
  * ```tsx
409
+ * // In NavigationView - id can be any string
405
410
  * <AdwNavigationView history={["home"]}>
406
- * <x.NavigationPage id="home" title="Home">
411
+ * <x.NavigationPage for={AdwNavigationView} id="home" title="Home">
407
412
  * <GtkLabel label="Welcome!" />
408
413
  * </x.NavigationPage>
409
- * <x.NavigationPage id="settings" title="Settings">
410
- * <GtkLabel label="Settings page" />
411
- * </x.NavigationPage>
412
414
  * </AdwNavigationView>
415
+ *
416
+ * // In NavigationSplitView - id is narrowed to "content" | "sidebar"
417
+ * <AdwNavigationSplitView>
418
+ * <x.NavigationPage for={AdwNavigationSplitView} id="sidebar" title="Sidebar">
419
+ * <GtkLabel label="Sidebar" />
420
+ * </x.NavigationPage>
421
+ * <x.NavigationPage for={AdwNavigationSplitView} id="content" title="Content">
422
+ * <GtkLabel label="Content" />
423
+ * </x.NavigationPage>
424
+ * </AdwNavigationSplitView>
413
425
  * ```
414
426
  */
415
427
  NavigationPage: "NavigationPage",
@@ -23,20 +23,20 @@ class ApplicationNode extends Node {
23
23
  this.container.setMenubar(this.menu.getMenu());
24
24
  return;
25
25
  }
26
- if (child instanceof WindowNode) {
26
+ if (child instanceof WindowNode && child.container instanceof Gtk.ApplicationWindow) {
27
27
  return;
28
28
  }
29
- throw new Error(`Cannot append '${child.typeName}' to 'Application': expected Window or MenuItem`);
29
+ throw new Error(`Cannot append '${child.typeName}' to 'Application': expected ApplicationWindow or MenuItem`);
30
30
  }
31
31
  insertBefore(child, before) {
32
32
  if (child instanceof MenuNode) {
33
33
  this.menu.insertBefore(child, before);
34
34
  return;
35
35
  }
36
- if (child instanceof WindowNode) {
36
+ if (child instanceof WindowNode && child.container instanceof Gtk.ApplicationWindow) {
37
37
  return;
38
38
  }
39
- throw new Error(`Cannot insert '${child.typeName}' into 'Application': expected Window or MenuItem`);
39
+ throw new Error(`Cannot insert '${child.typeName}' into 'Application': expected ApplicationWindow or MenuItem`);
40
40
  }
41
41
  removeChild(child) {
42
42
  if (child instanceof MenuNode) {
@@ -48,10 +48,10 @@ class ApplicationNode extends Node {
48
48
  }, CommitPriority.LOW);
49
49
  return;
50
50
  }
51
- if (child instanceof WindowNode) {
51
+ if (child instanceof WindowNode && child.container instanceof Gtk.ApplicationWindow) {
52
52
  return;
53
53
  }
54
- throw new Error(`Cannot remove '${child.typeName}' from 'Application': expected Window or MenuItem`);
54
+ throw new Error(`Cannot remove '${child.typeName}' from 'Application': expected ApplicationWindow or MenuItem`);
55
55
  }
56
56
  }
57
57
  registerNodeClass(ApplicationNode);
@@ -26,6 +26,7 @@ import "./pack.js";
26
26
  import "./popover-menu.js";
27
27
  import "./scale-mark.js";
28
28
  import "./scale.js";
29
+ import "./scrolled-window.js";
29
30
  import "./simple-list-item.js";
30
31
  import "./simple-list-view.js";
31
32
  import "./slot.js";
@@ -26,6 +26,7 @@ import "./pack.js";
26
26
  import "./popover-menu.js";
27
27
  import "./scale-mark.js";
28
28
  import "./scale.js";
29
+ import "./scrolled-window.js";
29
30
  import "./simple-list-item.js";
30
31
  import "./simple-list-view.js";
31
32
  import "./slot.js";
@@ -7,4 +7,15 @@ export const EVENT_CONTROLLER_PROPS = new Set([
7
7
  "onKeyPressed",
8
8
  "onKeyReleased",
9
9
  "onScroll",
10
+ "onDragPrepare",
11
+ "onDragBegin",
12
+ "onDragEnd",
13
+ "onDragCancel",
14
+ "dragActions",
15
+ "onDrop",
16
+ "onDropEnter",
17
+ "onDropLeave",
18
+ "onDropMotion",
19
+ "dropActions",
20
+ "dropTypes",
10
21
  ]);
@@ -35,7 +35,7 @@ export class ListItemRenderer {
35
35
  initialize() {
36
36
  signalStore.set(this, this.factory, "setup", (_self, listItem) => {
37
37
  const ptr = getNativeId(listItem.handle);
38
- const box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
38
+ const box = new Gtk.Box(Gtk.Orientation.VERTICAL);
39
39
  if (this.estimatedItemHeight !== undefined) {
40
40
  box.setSizeRequest(-1, this.estimatedItemHeight);
41
41
  }
@@ -39,7 +39,7 @@ export class TreeListItemRenderer {
39
39
  signalStore.set(this, this.factory, "setup", (_self, listItem) => {
40
40
  const ptr = getNativeId(listItem.handle);
41
41
  const expander = new Gtk.TreeExpander();
42
- const box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
42
+ const box = new Gtk.Box(Gtk.Orientation.VERTICAL);
43
43
  if (this.estimatedItemHeight !== undefined) {
44
44
  box.setSizeRequest(-1, this.estimatedItemHeight);
45
45
  }
@@ -53,7 +53,12 @@ class ListViewNode extends WidgetNode {
53
53
  if (!oldProps || oldProps.estimatedItemHeight !== newProps.estimatedItemHeight) {
54
54
  this.itemRenderer.setEstimatedItemHeight(newProps.estimatedItemHeight);
55
55
  }
56
+ const previousModel = this.list.getSelectionModel();
56
57
  this.list.updateProps(oldProps ? filterProps(oldProps, PROP_NAMES) : null, filterProps(newProps, PROP_NAMES));
58
+ const currentModel = this.list.getSelectionModel();
59
+ if (previousModel !== currentModel) {
60
+ this.container.setModel(currentModel);
61
+ }
57
62
  super.updateProps(oldProps ? filterProps(oldProps, PROP_NAMES) : null, filterProps(newProps, PROP_NAMES));
58
63
  }
59
64
  }
@@ -7,14 +7,17 @@ export type ListProps = {
7
7
  selected?: string[];
8
8
  onSelectionChanged?: (ids: string[]) => void;
9
9
  };
10
+ type SelectionModel = Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection;
10
11
  export declare class List extends VirtualNode<ListProps> {
11
12
  private store;
12
13
  private selectionModel;
13
14
  private handleSelectionChange?;
15
+ private pendingSelection?;
16
+ private selectionScheduled;
14
17
  constructor(props?: ListProps);
15
18
  private initSelectionHandler;
16
19
  getStore(): ListStore;
17
- getSelectionModel(): Gtk.SingleSelection | Gtk.MultiSelection;
20
+ getSelectionModel(): SelectionModel;
18
21
  appendChild(child: Node): void;
19
22
  insertBefore(child: Node, before: Node): void;
20
23
  removeChild(child: Node): void;
@@ -22,4 +25,6 @@ export declare class List extends VirtualNode<ListProps> {
22
25
  private createSelectionModel;
23
26
  private getSelection;
24
27
  private setSelection;
28
+ private applySelection;
25
29
  }
30
+ export {};
@@ -1,4 +1,5 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { CommitPriority, scheduleAfterCommit } from "../../scheduler.js";
2
3
  import { ListStore } from "../internal/list-store.js";
3
4
  import { signalStore } from "../internal/signal-store.js";
4
5
  import { ListItemNode } from "../list-item.js";
@@ -7,6 +8,8 @@ export class List extends VirtualNode {
7
8
  store;
8
9
  selectionModel;
9
10
  handleSelectionChange;
11
+ pendingSelection;
12
+ selectionScheduled = false;
10
13
  constructor(props = {}) {
11
14
  super("", {}, undefined);
12
15
  this.store = new ListStore();
@@ -71,13 +74,15 @@ export class List extends VirtualNode {
71
74
  createSelectionModel(mode) {
72
75
  const model = this.store.getModel();
73
76
  const selectionMode = mode ?? Gtk.SelectionMode.SINGLE;
74
- const selectionModel = selectionMode === Gtk.SelectionMode.MULTIPLE
75
- ? new Gtk.MultiSelection(model)
76
- : new Gtk.SingleSelection(model);
77
- if (selectionModel instanceof Gtk.SingleSelection) {
78
- selectionModel.setAutoselect(false);
79
- selectionModel.setCanUnselect(true);
77
+ if (selectionMode === Gtk.SelectionMode.NONE) {
78
+ return new Gtk.NoSelection(model);
80
79
  }
80
+ if (selectionMode === Gtk.SelectionMode.MULTIPLE) {
81
+ return new Gtk.MultiSelection(model);
82
+ }
83
+ const selectionModel = new Gtk.SingleSelection(model);
84
+ selectionModel.setAutoselect(selectionMode === Gtk.SelectionMode.BROWSE);
85
+ selectionModel.setCanUnselect(selectionMode !== Gtk.SelectionMode.BROWSE);
81
86
  return selectionModel;
82
87
  }
83
88
  getSelection() {
@@ -95,6 +100,16 @@ export class List extends VirtualNode {
95
100
  return ids;
96
101
  }
97
102
  setSelection(ids) {
103
+ this.pendingSelection = ids;
104
+ if (!this.selectionScheduled) {
105
+ this.selectionScheduled = true;
106
+ scheduleAfterCommit(() => this.applySelection(), CommitPriority.LOW);
107
+ }
108
+ }
109
+ applySelection() {
110
+ this.selectionScheduled = false;
111
+ const ids = this.pendingSelection;
112
+ this.pendingSelection = undefined;
98
113
  const model = this.store.getModel();
99
114
  const nItems = model.getNItems();
100
115
  const selected = new Gtk.Bitset();
@@ -8,17 +8,20 @@ export type TreeListProps = {
8
8
  selected?: string[];
9
9
  onSelectionChanged?: (ids: string[]) => void;
10
10
  };
11
+ type SelectionModel = Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection;
11
12
  export declare class TreeList extends VirtualNode<TreeListProps> {
12
13
  private store;
13
14
  private treeListModel;
14
15
  private selectionModel;
15
16
  private handleSelectionChange?;
17
+ private pendingSelection?;
18
+ private selectionScheduled;
16
19
  constructor(props?: TreeListProps);
17
20
  private initSelectionHandler;
18
21
  private createChildModel;
19
22
  getStore(): TreeStore;
20
23
  getTreeListModel(): Gtk.TreeListModel;
21
- getSelectionModel(): Gtk.SingleSelection | Gtk.MultiSelection;
24
+ getSelectionModel(): SelectionModel;
22
25
  appendChild(child: Node): void;
23
26
  insertBefore(child: Node, before: Node): void;
24
27
  removeChild(child: Node): void;
@@ -26,4 +29,6 @@ export declare class TreeList extends VirtualNode<TreeListProps> {
26
29
  private createSelectionModel;
27
30
  private getSelection;
28
31
  private setSelection;
32
+ private applySelection;
29
33
  }
34
+ export {};
@@ -1,5 +1,5 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { scheduleAfterCommit } from "../../scheduler.js";
2
+ import { CommitPriority, scheduleAfterCommit } from "../../scheduler.js";
3
3
  import { signalStore } from "../internal/signal-store.js";
4
4
  import { TreeStore } from "../internal/tree-store.js";
5
5
  import { TreeListItemNode } from "../tree-list-item.js";
@@ -9,6 +9,8 @@ export class TreeList extends VirtualNode {
9
9
  treeListModel;
10
10
  selectionModel;
11
11
  handleSelectionChange;
12
+ pendingSelection;
13
+ selectionScheduled = false;
12
14
  constructor(props = {}) {
13
15
  super("", {}, undefined);
14
16
  this.store = new TreeStore();
@@ -117,13 +119,15 @@ export class TreeList extends VirtualNode {
117
119
  }
118
120
  createSelectionModel(mode) {
119
121
  const selectionMode = mode ?? Gtk.SelectionMode.SINGLE;
120
- const selectionModel = selectionMode === Gtk.SelectionMode.MULTIPLE
121
- ? new Gtk.MultiSelection(this.treeListModel)
122
- : new Gtk.SingleSelection(this.treeListModel);
123
- if (selectionModel instanceof Gtk.SingleSelection) {
124
- selectionModel.setAutoselect(false);
125
- selectionModel.setCanUnselect(true);
122
+ if (selectionMode === Gtk.SelectionMode.NONE) {
123
+ return new Gtk.NoSelection(this.treeListModel);
126
124
  }
125
+ if (selectionMode === Gtk.SelectionMode.MULTIPLE) {
126
+ return new Gtk.MultiSelection(this.treeListModel);
127
+ }
128
+ const selectionModel = new Gtk.SingleSelection(this.treeListModel);
129
+ selectionModel.setAutoselect(selectionMode === Gtk.SelectionMode.BROWSE);
130
+ selectionModel.setCanUnselect(selectionMode !== Gtk.SelectionMode.BROWSE);
127
131
  return selectionModel;
128
132
  }
129
133
  getSelection() {
@@ -143,6 +147,16 @@ export class TreeList extends VirtualNode {
143
147
  return ids;
144
148
  }
145
149
  setSelection(ids) {
150
+ this.pendingSelection = ids;
151
+ if (!this.selectionScheduled) {
152
+ this.selectionScheduled = true;
153
+ scheduleAfterCommit(() => this.applySelection(), CommitPriority.LOW);
154
+ }
155
+ }
156
+ applySelection() {
157
+ this.selectionScheduled = false;
158
+ const ids = this.pendingSelection;
159
+ this.pendingSelection = undefined;
146
160
  const nItems = this.treeListModel.getNItems();
147
161
  const selected = new Gtk.Bitset();
148
162
  const mask = Gtk.Bitset.newRange(0, nItems);
@@ -1,16 +1,11 @@
1
1
  import * as Adw from "@gtkx/ffi/adw";
2
- import type * as Gtk from "@gtkx/ffi/gtk";
3
2
  import type { NavigationPageProps } from "../jsx.js";
4
3
  import { SlotNode } from "./slot.js";
5
4
  type Props = Partial<NavigationPageProps>;
6
5
  export declare class NavigationPageNode extends SlotNode<Props> {
7
6
  static priority: number;
8
- private page?;
9
7
  static matches(type: string): boolean;
10
- getPage(): Adw.NavigationPage | undefined;
11
8
  updateProps(oldProps: Props | null, newProps: Props): void;
12
- private addPage;
13
- private removePage;
14
- protected onChildChange(oldChild: Gtk.Widget | null): void;
9
+ protected onChildChange(oldChild: Adw.NavigationPage | null): void;
15
10
  }
16
11
  export {};
@@ -1,57 +1,46 @@
1
- import { isObjectEqual } from "@gtkx/ffi";
2
1
  import * as Adw from "@gtkx/ffi/adw";
3
2
  import { registerNodeClass } from "../registry.js";
4
3
  import { SlotNode } from "./slot.js";
5
4
  export class NavigationPageNode extends SlotNode {
6
5
  static priority = 1;
7
- page;
8
6
  static matches(type) {
9
7
  return type === "NavigationPage";
10
8
  }
11
- getPage() {
12
- return this.page;
13
- }
14
9
  updateProps(oldProps, newProps) {
15
10
  super.updateProps(oldProps, newProps);
16
- if (!this.page) {
11
+ const child = this.child;
12
+ if (!(child instanceof Adw.NavigationPage)) {
17
13
  return;
18
14
  }
19
15
  if (newProps.id !== undefined && (!oldProps || oldProps.id !== newProps.id)) {
20
- this.page.setTag(newProps.id);
16
+ child.setTag(newProps.id);
21
17
  }
22
18
  if (newProps.title !== undefined && (!oldProps || oldProps.title !== newProps.title)) {
23
- this.page.setTitle(newProps.title);
19
+ child.setTitle(newProps.title);
24
20
  }
25
21
  if (newProps.canPop !== undefined && (!oldProps || oldProps.canPop !== newProps.canPop)) {
26
- this.page.setCanPop(newProps.canPop);
22
+ child.setCanPop(newProps.canPop);
27
23
  }
28
24
  }
29
- addPage() {
30
- const child = this.getChild();
31
- const parent = this.getParent();
25
+ onChildChange(oldChild) {
26
+ const navigationView = this.getParent();
32
27
  const title = this.props.title ?? "";
33
- const page = this.props.id
34
- ? Adw.NavigationPage.newWithTag(child, title, this.props.id)
35
- : new Adw.NavigationPage(child, title);
36
- parent.add(page);
37
- this.page = page;
38
- this.updateProps(null, this.props);
39
- }
40
- removePage(oldChild) {
41
- const parent = this.getParent();
42
- if (!oldChild || !this.page) {
43
- return;
28
+ if (this.child) {
29
+ this.child = this.props.id
30
+ ? Adw.NavigationPage.newWithTag(this.child, title, this.props.id)
31
+ : new Adw.NavigationPage(this.child, title);
32
+ this.updateProps(null, this.props);
44
33
  }
45
- const pageChild = this.page.getChild();
46
- if (pageChild && isObjectEqual(pageChild, oldChild)) {
47
- parent.remove(this.page);
48
- this.page = undefined;
34
+ if (navigationView instanceof Adw.NavigationView) {
35
+ if (oldChild instanceof Adw.NavigationPage) {
36
+ navigationView.remove(oldChild);
37
+ }
38
+ if (this.child) {
39
+ navigationView.add(this.child);
40
+ }
49
41
  }
50
- }
51
- onChildChange(oldChild) {
52
- this.removePage(oldChild);
53
- if (this.child) {
54
- this.addPage();
42
+ else {
43
+ super.onChildChange(oldChild);
55
44
  }
56
45
  }
57
46
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { filterProps, isContainerType } from "./internal/utils.js";
4
+ import { WidgetNode } from "./widget.js";
5
+ const PROPS = ["hscrollbarPolicy", "vscrollbarPolicy"];
6
+ class ScrolledWindowNode extends WidgetNode {
7
+ static priority = 2;
8
+ static matches(_type, containerOrClass) {
9
+ return isContainerType(Gtk.ScrolledWindow, containerOrClass);
10
+ }
11
+ updateProps(oldProps, newProps) {
12
+ if (oldProps?.hscrollbarPolicy !== newProps.hscrollbarPolicy ||
13
+ oldProps?.vscrollbarPolicy !== newProps.vscrollbarPolicy) {
14
+ const hPolicy = newProps.hscrollbarPolicy ?? Gtk.PolicyType.AUTOMATIC;
15
+ const vPolicy = newProps.vscrollbarPolicy ?? Gtk.PolicyType.AUTOMATIC;
16
+ this.container.setPolicy(hPolicy, vPolicy);
17
+ }
18
+ super.updateProps(filterProps(oldProps ?? {}, PROPS), filterProps(newProps, PROPS));
19
+ }
20
+ }
21
+ registerNodeClass(ScrolledWindowNode);
@@ -17,11 +17,20 @@ export class SlotNode extends VirtualNode {
17
17
  }
18
18
  unmount() {
19
19
  if (this.parent && this.child) {
20
+ const parent = this.parent;
20
21
  const oldChild = this.child;
21
22
  this.child = undefined;
22
- this.onChildChange(oldChild ?? null);
23
+ queueMicrotask(() => {
24
+ if (parent.getRoot() !== null) {
25
+ this.parent = parent;
26
+ this.onChildChange(oldChild);
27
+ }
28
+ this.parent = undefined;
29
+ });
30
+ }
31
+ else {
32
+ this.parent = undefined;
23
33
  }
24
- this.parent = undefined;
25
34
  super.unmount();
26
35
  }
27
36
  getId() {