@gtkx/react 0.17.2 → 0.18.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.
Files changed (194) hide show
  1. package/README.md +7 -7
  2. package/dist/factory.d.ts +0 -1
  3. package/dist/factory.js +21 -8
  4. package/dist/generated/internal.d.ts +4 -51
  5. package/dist/generated/internal.js +626 -412
  6. package/dist/generated/jsx.d.ts +453 -958
  7. package/dist/host-config.d.ts +1 -1
  8. package/dist/host-config.js +18 -23
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/jsx.d.ts +579 -302
  12. package/dist/jsx.js +37 -179
  13. package/dist/metadata.d.ts +3 -0
  14. package/dist/metadata.js +26 -0
  15. package/dist/node.d.ts +20 -12
  16. package/dist/node.js +72 -17
  17. package/dist/nodes/adjustable.d.ts +3 -16
  18. package/dist/nodes/adjustable.js +5 -22
  19. package/dist/nodes/alert-dialog-response.d.ts +14 -1
  20. package/dist/nodes/alert-dialog-response.js +36 -62
  21. package/dist/nodes/animation.d.ts +37 -1
  22. package/dist/nodes/animation.js +162 -105
  23. package/dist/nodes/application.d.ts +11 -1
  24. package/dist/nodes/application.js +17 -38
  25. package/dist/nodes/calendar.d.ts +13 -0
  26. package/dist/nodes/calendar.js +10 -16
  27. package/dist/nodes/color-dialog-button.d.ts +13 -0
  28. package/dist/nodes/color-dialog-button.js +10 -38
  29. package/dist/nodes/column-view-column.d.ts +13 -11
  30. package/dist/nodes/column-view-column.js +27 -23
  31. package/dist/nodes/column-view.d.ts +31 -0
  32. package/dist/nodes/column-view.js +44 -44
  33. package/dist/nodes/container-slot.d.ts +15 -0
  34. package/dist/nodes/container-slot.js +68 -0
  35. package/dist/nodes/dialog.d.ts +6 -8
  36. package/dist/nodes/dialog.js +12 -13
  37. package/dist/nodes/drawing-area.d.ts +12 -0
  38. package/dist/nodes/drawing-area.js +24 -24
  39. package/dist/nodes/drop-down.d.ts +22 -0
  40. package/dist/nodes/drop-down.js +72 -0
  41. package/dist/nodes/event-controller.d.ts +8 -17
  42. package/dist/nodes/event-controller.js +20 -42
  43. package/dist/nodes/fixed-child.d.ts +18 -1
  44. package/dist/nodes/fixed-child.js +52 -36
  45. package/dist/nodes/font-dialog-button.d.ts +13 -0
  46. package/dist/nodes/font-dialog-button.js +12 -35
  47. package/dist/nodes/grid-child.d.ts +17 -1
  48. package/dist/nodes/grid-child.js +57 -37
  49. package/dist/nodes/grid-view.d.ts +24 -0
  50. package/dist/nodes/grid-view.js +73 -0
  51. package/dist/nodes/internal/base-item-renderer.d.ts +7 -9
  52. package/dist/nodes/internal/base-item-renderer.js +15 -18
  53. package/dist/nodes/internal/grid-item-renderer.d.ts +17 -0
  54. package/dist/nodes/internal/grid-item-renderer.js +59 -0
  55. package/dist/nodes/internal/list-item-renderer.d.ts +14 -9
  56. package/dist/nodes/internal/list-item-renderer.js +96 -35
  57. package/dist/nodes/internal/list-store.d.ts +5 -0
  58. package/dist/nodes/internal/list-store.js +39 -9
  59. package/dist/nodes/internal/predicates.d.ts +4 -19
  60. package/dist/nodes/internal/predicates.js +1 -20
  61. package/dist/nodes/internal/props.d.ts +5 -0
  62. package/dist/nodes/internal/props.js +42 -0
  63. package/dist/nodes/internal/{selection-model.d.ts → selection-model-controller.d.ts} +4 -9
  64. package/dist/nodes/internal/{selection-model.js → selection-model-controller.js} +6 -15
  65. package/dist/nodes/internal/signal-store.js +12 -5
  66. package/dist/nodes/internal/simple-list-store.d.ts +5 -0
  67. package/dist/nodes/internal/simple-list-store.js +42 -13
  68. package/dist/nodes/internal/text-buffer-controller.d.ts +4 -12
  69. package/dist/nodes/internal/text-buffer-controller.js +32 -33
  70. package/dist/nodes/internal/tree-store.d.ts +7 -0
  71. package/dist/nodes/internal/tree-store.js +75 -18
  72. package/dist/nodes/internal/widget.d.ts +7 -0
  73. package/dist/nodes/internal/widget.js +68 -0
  74. package/dist/nodes/level-bar.d.ts +10 -0
  75. package/dist/nodes/level-bar.js +11 -22
  76. package/dist/nodes/list-item.d.ts +17 -9
  77. package/dist/nodes/list-item.js +67 -12
  78. package/dist/nodes/list-view.d.ts +23 -0
  79. package/dist/nodes/list-view.js +27 -31
  80. package/dist/nodes/menu.d.ts +2 -4
  81. package/dist/nodes/menu.js +0 -6
  82. package/dist/nodes/models/grid.d.ts +27 -0
  83. package/dist/nodes/models/grid.js +68 -0
  84. package/dist/nodes/models/list.d.ts +15 -13
  85. package/dist/nodes/models/list.js +48 -26
  86. package/dist/nodes/models/menu.d.ts +15 -16
  87. package/dist/nodes/models/menu.js +63 -93
  88. package/dist/nodes/navigation-page.d.ts +16 -10
  89. package/dist/nodes/navigation-page.js +108 -31
  90. package/dist/nodes/navigation-view.d.ts +15 -0
  91. package/dist/nodes/navigation-view.js +15 -65
  92. package/dist/nodes/notebook-page-tab.d.ts +10 -12
  93. package/dist/nodes/notebook-page-tab.js +24 -27
  94. package/dist/nodes/notebook-page.d.ts +19 -16
  95. package/dist/nodes/notebook-page.js +75 -56
  96. package/dist/nodes/notebook.d.ts +10 -1
  97. package/dist/nodes/notebook.js +10 -22
  98. package/dist/nodes/overlay-child.d.ts +17 -1
  99. package/dist/nodes/overlay-child.js +53 -75
  100. package/dist/nodes/popover-menu.d.ts +15 -0
  101. package/dist/nodes/popover-menu.js +13 -26
  102. package/dist/nodes/scale.d.ts +8 -0
  103. package/dist/nodes/scale.js +2 -11
  104. package/dist/nodes/scrolled-window.d.ts +9 -0
  105. package/dist/nodes/scrolled-window.js +5 -11
  106. package/dist/nodes/search-bar.d.ts +9 -0
  107. package/dist/nodes/search-bar.js +8 -33
  108. package/dist/nodes/shortcut-controller.d.ts +9 -1
  109. package/dist/nodes/shortcut-controller.js +12 -25
  110. package/dist/nodes/shortcut.d.ts +11 -33
  111. package/dist/nodes/shortcut.js +19 -15
  112. package/dist/nodes/slot.d.ts +16 -15
  113. package/dist/nodes/slot.js +63 -57
  114. package/dist/nodes/source-view.d.ts +16 -0
  115. package/dist/nodes/source-view.js +44 -44
  116. package/dist/nodes/stack-page.d.ts +21 -1
  117. package/dist/nodes/stack-page.js +68 -17
  118. package/dist/nodes/stack.d.ts +11 -0
  119. package/dist/nodes/stack.js +8 -26
  120. package/dist/nodes/text-anchor.d.ts +11 -30
  121. package/dist/nodes/text-anchor.js +20 -22
  122. package/dist/nodes/text-content.d.ts +1 -0
  123. package/dist/nodes/text-content.js +1 -1
  124. package/dist/nodes/text-paintable.d.ts +10 -15
  125. package/dist/nodes/text-paintable.js +16 -9
  126. package/dist/nodes/text-segment.d.ts +12 -10
  127. package/dist/nodes/text-segment.js +19 -11
  128. package/dist/nodes/text-tag.d.ts +20 -119
  129. package/dist/nodes/text-tag.js +153 -119
  130. package/dist/nodes/text-view.d.ts +13 -18
  131. package/dist/nodes/text-view.js +17 -17
  132. package/dist/nodes/toggle-group.d.ts +9 -0
  133. package/dist/nodes/toggle-group.js +8 -33
  134. package/dist/nodes/toggle.d.ts +15 -1
  135. package/dist/nodes/toggle.js +34 -52
  136. package/dist/nodes/virtual.d.ts +3 -10
  137. package/dist/nodes/virtual.js +1 -14
  138. package/dist/nodes/web-view.d.ts +9 -0
  139. package/dist/nodes/web-view.js +10 -24
  140. package/dist/nodes/widget.d.ts +17 -13
  141. package/dist/nodes/widget.js +185 -112
  142. package/dist/nodes/window.d.ts +20 -21
  143. package/dist/nodes/window.js +54 -35
  144. package/dist/registry.d.ts +17 -6
  145. package/dist/registry.js +104 -5
  146. package/dist/render.d.ts +1 -10
  147. package/dist/render.js +1 -13
  148. package/package.json +6 -6
  149. package/dist/animation/css-builder.d.ts +0 -3
  150. package/dist/animation/css-builder.js +0 -53
  151. package/dist/animation/types.d.ts +0 -120
  152. package/dist/animation/types.js +0 -1
  153. package/dist/nodes/abstract/positional-child.d.ts +0 -9
  154. package/dist/nodes/abstract/positional-child.js +0 -29
  155. package/dist/nodes/abstract/virtual-container.d.ts +0 -21
  156. package/dist/nodes/abstract/virtual-container.js +0 -68
  157. package/dist/nodes/abstract/virtual-single-child.d.ts +0 -18
  158. package/dist/nodes/abstract/virtual-single-child.js +0 -55
  159. package/dist/nodes/action-row-child.d.ts +0 -1
  160. package/dist/nodes/action-row-child.js +0 -30
  161. package/dist/nodes/autowrapped.d.ts +0 -1
  162. package/dist/nodes/autowrapped.js +0 -115
  163. package/dist/nodes/expander-row-child.d.ts +0 -1
  164. package/dist/nodes/expander-row-child.js +0 -30
  165. package/dist/nodes/grid.d.ts +0 -1
  166. package/dist/nodes/grid.js +0 -41
  167. package/dist/nodes/index.d.ts +0 -56
  168. package/dist/nodes/index.js +0 -56
  169. package/dist/nodes/internal/child-attachment.d.ts +0 -26
  170. package/dist/nodes/internal/child-attachment.js +0 -48
  171. package/dist/nodes/internal/deferred-action.d.ts +0 -9
  172. package/dist/nodes/internal/deferred-action.js +0 -22
  173. package/dist/nodes/internal/text-tag-styles.d.ts +0 -43
  174. package/dist/nodes/internal/text-tag-styles.js +0 -52
  175. package/dist/nodes/internal/tree-list-item-renderer.d.ts +0 -26
  176. package/dist/nodes/internal/tree-list-item-renderer.js +0 -134
  177. package/dist/nodes/internal/utils.d.ts +0 -12
  178. package/dist/nodes/internal/utils.js +0 -92
  179. package/dist/nodes/models/tree-list.d.ts +0 -28
  180. package/dist/nodes/models/tree-list.js +0 -113
  181. package/dist/nodes/pack-child.d.ts +0 -1
  182. package/dist/nodes/pack-child.js +0 -30
  183. package/dist/nodes/simple-list-item.d.ts +0 -9
  184. package/dist/nodes/simple-list-item.js +0 -9
  185. package/dist/nodes/simple-list-view.d.ts +0 -1
  186. package/dist/nodes/simple-list-view.js +0 -74
  187. package/dist/nodes/toolbar-child.d.ts +0 -1
  188. package/dist/nodes/toolbar-child.js +0 -30
  189. package/dist/nodes/tree-list-item.d.ts +0 -22
  190. package/dist/nodes/tree-list-item.js +0 -90
  191. package/dist/nodes/tree-list-view.d.ts +0 -1
  192. package/dist/nodes/tree-list-view.js +0 -77
  193. package/dist/scheduler.d.ts +0 -26
  194. package/dist/scheduler.js +0 -42
@@ -1 +1,21 @@
1
- export {};
1
+ import type { StackPageProps } from "../jsx.js";
2
+ import type { Node } from "../node.js";
3
+ import type { StackWidget } from "../registry.js";
4
+ import { VirtualNode } from "./virtual.js";
5
+ import { WidgetNode } from "./widget.js";
6
+ export declare class StackPageNode extends VirtualNode<StackPageProps, WidgetNode<StackWidget>, WidgetNode> {
7
+ private page;
8
+ isValidChild(child: Node): boolean;
9
+ isValidParent(parent: Node): boolean;
10
+ setParent(parent: WidgetNode<StackWidget> | null): void;
11
+ appendChild(child: WidgetNode): void;
12
+ removeChild(child: WidgetNode): void;
13
+ commitUpdate(oldProps: StackPageProps | null, newProps: StackPageProps): void;
14
+ detachDeletedInstance(): void;
15
+ private getChildWidget;
16
+ private getParentWidget;
17
+ private applyOwnProps;
18
+ private onChildChange;
19
+ private addPage;
20
+ private removePage;
21
+ }
@@ -1,18 +1,70 @@
1
- import { isObjectEqual } from "@gtkx/ffi";
2
1
  import * as Adw from "@gtkx/ffi/adw";
3
- import { registerNodeClass } from "../registry.js";
4
- import { hasChanged } from "./internal/utils.js";
5
- import { SlotNode } from "./slot.js";
6
- class StackPageNode extends SlotNode {
7
- static priority = 1;
2
+ import * as Gtk from "@gtkx/ffi/gtk";
3
+ import { hasChanged } from "./internal/props.js";
4
+ import { VirtualNode } from "./virtual.js";
5
+ import { WidgetNode } from "./widget.js";
6
+ export class StackPageNode extends VirtualNode {
8
7
  page = null;
9
- static matches(type) {
10
- return type === "StackPage";
8
+ isValidChild(child) {
9
+ return child instanceof WidgetNode;
11
10
  }
12
- updateProps(oldProps, newProps) {
13
- super.updateProps(oldProps, newProps);
11
+ isValidParent(parent) {
12
+ return (parent instanceof WidgetNode &&
13
+ (parent.container instanceof Gtk.Stack || parent.container instanceof Adw.ViewStack));
14
+ }
15
+ setParent(parent) {
16
+ const previousParent = this.parent;
17
+ if (previousParent && !parent) {
18
+ const childWidget = this.children[0]?.container ?? null;
19
+ if (childWidget) {
20
+ this.removePage(childWidget);
21
+ }
22
+ this.page = null;
23
+ }
24
+ super.setParent(parent);
25
+ if (parent && this.children[0]) {
26
+ this.onChildChange(null);
27
+ }
28
+ }
29
+ appendChild(child) {
30
+ const oldChildWidget = this.children[0]?.container ?? null;
31
+ super.appendChild(child);
32
+ if (this.parent) {
33
+ this.onChildChange(oldChildWidget);
34
+ }
35
+ }
36
+ removeChild(child) {
37
+ const oldChildWidget = child.container;
38
+ super.removeChild(child);
39
+ if (this.parent && oldChildWidget) {
40
+ this.onChildChange(oldChildWidget);
41
+ }
42
+ }
43
+ commitUpdate(oldProps, newProps) {
44
+ super.commitUpdate(oldProps, newProps);
14
45
  this.applyOwnProps(oldProps, newProps);
15
46
  }
47
+ detachDeletedInstance() {
48
+ const childWidget = this.children[0]?.container ?? null;
49
+ if (childWidget && this.parent) {
50
+ this.removePage(childWidget);
51
+ }
52
+ this.page = null;
53
+ super.detachDeletedInstance();
54
+ }
55
+ getChildWidget() {
56
+ const child = this.children[0];
57
+ if (!child) {
58
+ throw new Error("Expected child widget to be set on StackPageNode");
59
+ }
60
+ return child.container;
61
+ }
62
+ getParentWidget() {
63
+ if (!this.parent) {
64
+ throw new Error("Expected parent widget to be set on StackPageNode");
65
+ }
66
+ return this.parent.container;
67
+ }
16
68
  applyOwnProps(oldProps, newProps) {
17
69
  if (!this.page) {
18
70
  return;
@@ -38,13 +90,13 @@ class StackPageNode extends SlotNode {
38
90
  }
39
91
  onChildChange(oldChild) {
40
92
  this.removePage(oldChild);
41
- if (this.child) {
93
+ if (this.children[0]) {
42
94
  this.addPage();
43
95
  }
44
96
  }
45
97
  addPage() {
46
- const child = this.getChild();
47
- const parent = this.getParent();
98
+ const child = this.getChildWidget();
99
+ const parent = this.getParentWidget();
48
100
  let page;
49
101
  if (parent instanceof Adw.ViewStack) {
50
102
  if (this.props.title && this.props.iconName) {
@@ -72,17 +124,16 @@ class StackPageNode extends SlotNode {
72
124
  }
73
125
  }
74
126
  this.page = page;
75
- this.updateProps(null, this.props);
127
+ this.commitUpdate(null, this.props);
76
128
  }
77
129
  removePage(oldChild) {
78
- const parent = this.getParent();
130
+ const parent = this.getParentWidget();
79
131
  if (!oldChild) {
80
132
  return;
81
133
  }
82
134
  const currentParent = oldChild.getParent();
83
- if (currentParent && isObjectEqual(currentParent, parent)) {
135
+ if (currentParent && currentParent === parent) {
84
136
  parent.remove(oldChild);
85
137
  }
86
138
  }
87
139
  }
88
- registerNodeClass(StackPageNode);
@@ -1 +1,12 @@
1
+ import type { AdwViewStackProps, GtkStackProps } from "../jsx.js";
2
+ import type { StackWidget } from "../registry.js";
3
+ import { WidgetNode } from "./widget.js";
4
+ declare const OWN_PROPS: readonly ["page", "onPageChanged"];
5
+ type StackProps = Omit<Pick<GtkStackProps | AdwViewStackProps, (typeof OWN_PROPS)[number]>, "onPageChanged"> & {
6
+ onPageChanged?: ((page: string | null, self: StackWidget) => void) | null;
7
+ };
8
+ export declare class StackNode extends WidgetNode<StackWidget, StackProps> {
9
+ commitUpdate(oldProps: StackProps | null, newProps: StackProps): void;
10
+ private applyOwnProps;
11
+ }
1
12
  export {};
@@ -1,38 +1,20 @@
1
- import { STACK_CLASSES } from "../generated/internal.js";
2
- import { registerNodeClass } from "../registry.js";
3
- import { CommitPriority, scheduleAfterCommit } from "../scheduler.js";
4
- import { filterProps, hasChanged, matchesAnyClass } from "./internal/utils.js";
1
+ import { filterProps, hasChanged } from "./internal/props.js";
5
2
  import { WidgetNode } from "./widget.js";
6
3
  const OWN_PROPS = ["page", "onPageChanged"];
7
- class StackNode extends WidgetNode {
8
- static priority = 1;
9
- static matches(_type, containerOrClass) {
10
- return matchesAnyClass(STACK_CLASSES, containerOrClass);
11
- }
12
- updateProps(oldProps, newProps) {
13
- super.updateProps(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
4
+ export class StackNode extends WidgetNode {
5
+ commitUpdate(oldProps, newProps) {
6
+ super.commitUpdate(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
14
7
  this.applyOwnProps(oldProps, newProps);
15
8
  }
16
9
  applyOwnProps(oldProps, newProps) {
17
10
  if (newProps.page && this.container.getVisibleChildName() !== newProps.page) {
18
- const page = newProps.page;
19
- scheduleAfterCommit(() => {
20
- if (this.container.getChildByName(page)) {
21
- this.container.setVisibleChildName(page);
22
- }
23
- }, CommitPriority.NORMAL);
11
+ if (this.container.getChildByName(newProps.page)) {
12
+ this.container.setVisibleChildName(newProps.page);
13
+ }
24
14
  }
25
15
  if (hasChanged(oldProps, newProps, "onPageChanged")) {
26
16
  const { onPageChanged } = newProps;
27
- if (onPageChanged) {
28
- this.signalStore.set(this, this.container, "notify::visible-child-name", (self) => {
29
- onPageChanged(self.getVisibleChildName(), self);
30
- });
31
- }
32
- else {
33
- this.signalStore.set(this, this.container, "notify::visible-child-name", null);
34
- }
17
+ this.signalStore.set(this, this.container, "notify::visible-child-name", onPageChanged ? (self) => onPageChanged(self.getVisibleChildName(), self) : undefined);
35
18
  }
36
19
  }
37
20
  }
38
- registerNodeClass(StackNode);
@@ -1,41 +1,22 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import type { ReactNode } from "react";
2
+ import type { TextAnchorProps } from "../jsx.js";
3
3
  import type { Node } from "../node.js";
4
+ import { type TextContentParent } from "./text-content.js";
4
5
  import { VirtualNode } from "./virtual.js";
5
- /**
6
- * Props for the TextAnchor virtual element.
7
- *
8
- * Used to declaratively embed widgets within text content in a TextBuffer.
9
- * The anchor is placed at the current position in the text flow.
10
- *
11
- * @example
12
- * ```tsx
13
- * <GtkTextView>
14
- * <x.TextBuffer>
15
- * Click here: <x.TextAnchor>
16
- * <GtkButton label="Click me" />
17
- * </x.TextAnchor> to continue.
18
- * </x.TextBuffer>
19
- * </GtkTextView>
20
- * ```
21
- */
22
- export type TextAnchorProps = {
23
- /** The widget to embed at this anchor position */
24
- children?: ReactNode;
25
- };
26
- export declare class TextAnchorNode extends VirtualNode<TextAnchorProps> {
27
- static priority: number;
6
+ import { WidgetNode } from "./widget.js";
7
+ export declare class TextAnchorNode extends VirtualNode<TextAnchorProps, Node & TextContentParent, WidgetNode> {
28
8
  private textView;
29
9
  private buffer;
30
10
  private anchor;
31
- private widgetChild;
32
- bufferOffset: number;
33
- static matches(type: string): boolean;
11
+ private bufferOffset;
12
+ getBufferOffset(): number;
13
+ setBufferOffset(offset: number): void;
14
+ isValidChild(child: Node): boolean;
15
+ isValidParent(parent: Node): boolean;
34
16
  getLength(): number;
35
17
  getText(): string;
36
18
  setTextViewAndBuffer(textView: Gtk.TextView, buffer: Gtk.TextBuffer): void;
37
19
  private setupAnchor;
38
- appendChild(child: Node): void;
39
- removeChild(child: Node): void;
40
- unmount(): void;
20
+ appendChild(child: WidgetNode): void;
21
+ detachDeletedInstance(): void;
41
22
  }
@@ -1,23 +1,30 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { registerNodeClass } from "../registry.js";
2
+ import { TEXT_OBJECT_REPLACEMENT } from "./text-content.js";
3
+ import { isTextContentParent } from "./text-segment.js";
3
4
  import { VirtualNode } from "./virtual.js";
4
5
  import { WidgetNode } from "./widget.js";
5
- const PLACEHOLDER = "\uFFFC";
6
6
  export class TextAnchorNode extends VirtualNode {
7
- static priority = 1;
8
7
  textView = null;
9
8
  buffer = null;
10
9
  anchor = null;
11
- widgetChild = null;
12
10
  bufferOffset = 0;
13
- static matches(type) {
14
- return type === "TextAnchor";
11
+ getBufferOffset() {
12
+ return this.bufferOffset;
13
+ }
14
+ setBufferOffset(offset) {
15
+ this.bufferOffset = offset;
16
+ }
17
+ isValidChild(child) {
18
+ return child instanceof WidgetNode;
19
+ }
20
+ isValidParent(parent) {
21
+ return isTextContentParent(parent);
15
22
  }
16
23
  getLength() {
17
24
  return 1;
18
25
  }
19
26
  getText() {
20
- return PLACEHOLDER;
27
+ return TEXT_OBJECT_REPLACEMENT;
21
28
  }
22
29
  setTextViewAndBuffer(textView, buffer) {
23
30
  this.textView = textView;
@@ -30,30 +37,21 @@ export class TextAnchorNode extends VirtualNode {
30
37
  const iter = new Gtk.TextIter();
31
38
  this.buffer.getIterAtOffset(iter, this.bufferOffset);
32
39
  this.anchor = this.buffer.createChildAnchor(iter);
33
- if (this.widgetChild?.container && this.anchor) {
34
- this.textView.addChildAtAnchor(this.widgetChild.container, this.anchor);
40
+ const widgetChild = this.children[0];
41
+ if (widgetChild?.container && this.anchor) {
42
+ this.textView.addChildAtAnchor(widgetChild.container, this.anchor);
35
43
  }
36
44
  }
37
45
  appendChild(child) {
38
- if (!(child instanceof WidgetNode)) {
39
- throw new Error(`TextAnchor can only contain widget children, got '${child.typeName}'`);
40
- }
41
- this.widgetChild = child;
46
+ super.appendChild(child);
42
47
  if (this.textView && this.anchor && child.container) {
43
48
  this.textView.addChildAtAnchor(child.container, this.anchor);
44
49
  }
45
50
  }
46
- removeChild(child) {
47
- if (child === this.widgetChild) {
48
- this.widgetChild = null;
49
- }
50
- }
51
- unmount() {
51
+ detachDeletedInstance() {
52
52
  this.anchor = null;
53
- this.widgetChild = null;
54
53
  this.buffer = null;
55
54
  this.textView = null;
56
- super.unmount();
55
+ super.detachDeletedInstance();
57
56
  }
58
57
  }
59
- registerNodeClass(TextAnchorNode);
@@ -2,6 +2,7 @@ import type { TextAnchorNode } from "./text-anchor.js";
2
2
  import type { TextPaintableNode } from "./text-paintable.js";
3
3
  import type { TextSegmentNode } from "./text-segment.js";
4
4
  import type { TextTagNode } from "./text-tag.js";
5
+ export declare const TEXT_OBJECT_REPLACEMENT = "\uFFFC";
5
6
  export type TextContentChild = TextSegmentNode | TextTagNode | TextAnchorNode | TextPaintableNode;
6
7
  export type TextContentParent = {
7
8
  onChildInserted(child: TextContentChild): void;
@@ -1 +1 @@
1
- export {};
1
+ export const TEXT_OBJECT_REPLACEMENT = "\uFFFC";
@@ -1,23 +1,18 @@
1
- import type * as Gdk from "@gtkx/ffi/gdk";
2
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { TextPaintableProps } from "../jsx.js";
3
+ import type { Node } from "../node.js";
4
+ import { type TextContentParent } from "./text-content.js";
3
5
  import { VirtualNode } from "./virtual.js";
4
- /**
5
- * Props for the TextPaintable virtual element.
6
- *
7
- * Used to embed inline images or icons within text content in a GtkTextView.
8
- */
9
- export type TextPaintableProps = {
10
- /** The paintable (image, icon, etc.) to embed inline with the text */
11
- paintable: Gdk.Paintable;
12
- };
13
- export declare class TextPaintableNode extends VirtualNode<TextPaintableProps> {
14
- static priority: number;
6
+ export declare class TextPaintableNode extends VirtualNode<TextPaintableProps, Node & TextContentParent, never> {
7
+ isValidChild(_child: Node): boolean;
8
+ isValidParent(parent: Node): boolean;
15
9
  private buffer;
16
- bufferOffset: number;
17
- static matches(type: string): boolean;
10
+ private bufferOffset;
11
+ getBufferOffset(): number;
12
+ setBufferOffset(offset: number): void;
18
13
  getLength(): number;
19
14
  getText(): string;
20
15
  setTextViewAndBuffer(_textView: Gtk.TextView, buffer: Gtk.TextBuffer): void;
21
16
  private insertPaintable;
22
- unmount(): void;
17
+ detachDeletedInstance(): void;
23
18
  }
@@ -1,19 +1,27 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import { registerNodeClass } from "../registry.js";
2
+ import { TEXT_OBJECT_REPLACEMENT } from "./text-content.js";
3
+ import { isTextContentParent } from "./text-segment.js";
3
4
  import { VirtualNode } from "./virtual.js";
4
- const PLACEHOLDER = "\uFFFC";
5
5
  export class TextPaintableNode extends VirtualNode {
6
- static priority = 1;
6
+ isValidChild(_child) {
7
+ return false;
8
+ }
9
+ isValidParent(parent) {
10
+ return isTextContentParent(parent);
11
+ }
7
12
  buffer = null;
8
13
  bufferOffset = 0;
9
- static matches(type) {
10
- return type === "TextPaintable";
14
+ getBufferOffset() {
15
+ return this.bufferOffset;
16
+ }
17
+ setBufferOffset(offset) {
18
+ this.bufferOffset = offset;
11
19
  }
12
20
  getLength() {
13
21
  return 1;
14
22
  }
15
23
  getText() {
16
- return PLACEHOLDER;
24
+ return TEXT_OBJECT_REPLACEMENT;
17
25
  }
18
26
  setTextViewAndBuffer(_textView, buffer) {
19
27
  this.buffer = buffer;
@@ -26,9 +34,8 @@ export class TextPaintableNode extends VirtualNode {
26
34
  this.buffer.getIterAtOffset(iter, this.bufferOffset);
27
35
  this.buffer.insertPaintable(iter, this.props.paintable);
28
36
  }
29
- unmount() {
37
+ detachDeletedInstance() {
30
38
  this.buffer = null;
31
- super.unmount();
39
+ super.detachDeletedInstance();
32
40
  }
33
41
  }
34
- registerNodeClass(TextPaintableNode);
@@ -1,15 +1,17 @@
1
+ import type { TextSegmentProps } from "../jsx.js";
2
+ import type { Node } from "../node.js";
1
3
  import type { TextContentParent } from "./text-content.js";
2
4
  import { VirtualNode } from "./virtual.js";
3
- export type TextSegmentProps = {
4
- text: string;
5
- };
6
- export declare class TextSegmentNode extends VirtualNode<TextSegmentProps> {
7
- static priority: number;
8
- private parent;
9
- bufferOffset: number;
10
- static matches(type: string): boolean;
11
- setParent(parent: TextContentParent): void;
5
+ type TextSegmentParent = Node & TextContentParent;
6
+ export declare class TextSegmentNode extends VirtualNode<TextSegmentProps, TextSegmentParent, never> {
7
+ private bufferOffset;
8
+ getBufferOffset(): number;
9
+ setBufferOffset(offset: number): void;
10
+ isValidChild(_child: Node): boolean;
11
+ isValidParent(parent: Node): boolean;
12
12
  getText(): string;
13
13
  getLength(): number;
14
- updateProps(oldProps: TextSegmentProps | null, newProps: TextSegmentProps): void;
14
+ commitUpdate(oldProps: TextSegmentProps | null, newProps: TextSegmentProps): void;
15
15
  }
16
+ export declare function isTextContentParent(node: Node): node is TextSegmentParent;
17
+ export {};
@@ -1,15 +1,18 @@
1
- import { registerNodeClass } from "../registry.js";
2
- import { hasChanged } from "./internal/utils.js";
1
+ import { hasChanged } from "./internal/props.js";
3
2
  import { VirtualNode } from "./virtual.js";
4
3
  export class TextSegmentNode extends VirtualNode {
5
- static priority = 1;
6
- parent = null;
7
4
  bufferOffset = 0;
8
- static matches(type) {
9
- return type === "TextSegment";
5
+ getBufferOffset() {
6
+ return this.bufferOffset;
10
7
  }
11
- setParent(parent) {
12
- this.parent = parent;
8
+ setBufferOffset(offset) {
9
+ this.bufferOffset = offset;
10
+ }
11
+ isValidChild(_child) {
12
+ return false;
13
+ }
14
+ isValidParent(parent) {
15
+ return isTextContentParent(parent);
13
16
  }
14
17
  getText() {
15
18
  return this.props.text;
@@ -17,13 +20,18 @@ export class TextSegmentNode extends VirtualNode {
17
20
  getLength() {
18
21
  return this.props.text.length;
19
22
  }
20
- updateProps(oldProps, newProps) {
23
+ commitUpdate(oldProps, newProps) {
21
24
  const oldText = oldProps?.text ?? "";
22
25
  const newText = newProps.text;
23
- super.updateProps(oldProps, newProps);
26
+ super.commitUpdate(oldProps, newProps);
24
27
  if (hasChanged(oldProps, newProps, "text") && this.parent) {
25
28
  this.parent.onChildTextChanged(this, oldText.length, newText.length);
26
29
  }
27
30
  }
28
31
  }
29
- registerNodeClass(TextSegmentNode);
32
+ export function isTextContentParent(node) {
33
+ const candidate = node;
34
+ return (typeof candidate.onChildInserted === "function" &&
35
+ typeof candidate.onChildRemoved === "function" &&
36
+ typeof candidate.onChildTextChanged === "function");
37
+ }
@@ -1,136 +1,37 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import type * as Pango from "@gtkx/ffi/pango";
3
- import type { ReactNode } from "react";
2
+ import type { TextTagProps } from "../jsx.js";
4
3
  import type { Node } from "../node.js";
5
4
  import type { TextContentChild, TextContentParent } from "./text-content.js";
6
5
  import { TextSegmentNode } from "./text-segment.js";
7
6
  import { VirtualNode } from "./virtual.js";
8
- /**
9
- * Props for the TextTag virtual element.
10
- *
11
- * Used to declaratively define and apply text formatting to content within a TextBuffer.
12
- *
13
- * @example
14
- * ```tsx
15
- * <GtkTextView>
16
- * <x.TextBuffer>
17
- * Hello <x.TextTag id="bold" weight={Pango.Weight.BOLD}>bold</x.TextTag> world
18
- * </x.TextBuffer>
19
- * </GtkTextView>
20
- * ```
21
- */
22
- export type TextTagProps = {
23
- /** Unique identifier for this tag in the tag table */
24
- id: string;
25
- /** Priority of this tag (higher wins when multiple tags affect same property) */
26
- priority?: number;
27
- /** Background color as a string (e.g., "red", "#ff0000") */
28
- background?: string;
29
- /** Whether the background fills the entire line height */
30
- backgroundFullHeight?: boolean;
31
- /** Foreground (text) color as a string */
32
- foreground?: string;
33
- /** Font family name (e.g., "Sans", "Monospace") */
34
- family?: string;
35
- /** Font description string (e.g., "Sans Italic 12") */
36
- font?: string;
37
- /** Font size in points */
38
- sizePoints?: number;
39
- /** Font size in Pango units */
40
- size?: number;
41
- /** Font size scale factor relative to default */
42
- scale?: number;
43
- /** Font weight (use Pango.Weight constants) */
44
- weight?: Pango.Weight | number;
45
- /** Font style (use Pango.Style constants) */
46
- style?: Pango.Style;
47
- /** Font stretch (use Pango.Stretch constants) */
48
- stretch?: Pango.Stretch;
49
- /** Font variant (use Pango.Variant constants) */
50
- variant?: Pango.Variant;
51
- /** Whether to strike through the text */
52
- strikethrough?: boolean;
53
- /** Underline style (use Pango.Underline constants) */
54
- underline?: Pango.Underline;
55
- /** Overline style (use Pango.Overline constants) */
56
- overline?: Pango.Overline;
57
- /** Offset of text above baseline in Pango units (negative = below) */
58
- rise?: number;
59
- /** Extra spacing between characters in Pango units */
60
- letterSpacing?: number;
61
- /** Factor to scale line height by */
62
- lineHeight?: number;
63
- /** Left margin in pixels */
64
- leftMargin?: number;
65
- /** Right margin in pixels */
66
- rightMargin?: number;
67
- /** Paragraph indent in pixels (negative = hanging) */
68
- indent?: number;
69
- /** Pixels of blank space above paragraphs */
70
- pixelsAboveLines?: number;
71
- /** Pixels of blank space below paragraphs */
72
- pixelsBelowLines?: number;
73
- /** Pixels of blank space between wrapped lines */
74
- pixelsInsideWrap?: number;
75
- /** Text justification */
76
- justification?: Gtk.Justification;
77
- /** Text direction */
78
- direction?: Gtk.TextDirection;
79
- /** Wrap mode for line breaks */
80
- wrapMode?: Gtk.WrapMode;
81
- /** Whether the text can be modified */
82
- editable?: boolean;
83
- /** Whether the text is invisible/hidden */
84
- invisible?: boolean;
85
- /** Whether breaks are allowed */
86
- allowBreaks?: boolean;
87
- /** Whether to insert hyphens at breaks */
88
- insertHyphens?: boolean;
89
- /** Whether font fallback is enabled */
90
- fallback?: boolean;
91
- /** Whether margins accumulate */
92
- accumulativeMargin?: boolean;
93
- /** Paragraph background color as a string */
94
- paragraphBackground?: string;
95
- /** How to render invisible characters */
96
- showSpaces?: Pango.ShowFlags;
97
- /** How to transform text for display */
98
- textTransform?: Pango.TextTransform;
99
- /** OpenType font features as a string */
100
- fontFeatures?: string;
101
- /** Language code (e.g., "en-US") */
102
- language?: string;
103
- /** Text content and nested TextTag children */
104
- children?: ReactNode;
105
- };
106
- export declare class TextTagNode extends VirtualNode<TextTagProps> implements TextContentParent {
107
- static priority: number;
7
+ type TextTagParent = Node & TextContentParent;
8
+ export declare class TextTagNode extends VirtualNode<TextTagProps, TextTagParent, TextContentChild> implements TextContentParent {
108
9
  private buffer;
109
10
  private tag;
110
- private children;
111
- private parent;
112
- bufferOffset: number;
113
- static matches(type: string): boolean;
114
- setParent(parent: TextContentParent): void;
11
+ private bufferOffset;
12
+ getBufferOffset(): number;
13
+ setBufferOffset(offset: number): void;
14
+ isValidChild(child: Node): boolean;
15
+ isValidParent(parent: Node): boolean;
16
+ appendChild(child: TextContentChild): void;
17
+ removeChild(child: TextContentChild): void;
18
+ insertBefore(child: TextContentChild, before: TextContentChild): void;
19
+ commitUpdate(oldProps: TextTagProps | null, newProps: TextTagProps): void;
20
+ detachDeletedInstance(): void;
115
21
  setBuffer(buffer: Gtk.TextBuffer): void;
116
22
  hasBuffer(): boolean;
117
- private setupTag;
118
- private applyStyleProps;
119
23
  getText(): string;
120
24
  getLength(): number;
121
- getChildren(): TextContentChild[];
122
- private applyTagToRange;
123
- private removeTagFromBuffer;
124
25
  reapplyTag(): void;
125
- private updateChildOffsets;
126
26
  onChildInserted(child: TextContentChild): void;
127
27
  onChildRemoved(child: TextContentChild): void;
128
28
  onChildTextChanged(child: TextSegmentNode, oldLength: number, newLength: number): void;
129
- appendChild(child: Node): void;
130
- removeChild(child: Node): void;
131
- insertBefore(child: Node, before: Node): void;
29
+ private setupTag;
30
+ private applyOwnProps;
31
+ private applyStyleProps;
32
+ private applyTagToRange;
33
+ private removeTagFromBuffer;
34
+ private updateChildOffsets;
132
35
  private isTextContentChild;
133
- private setChildParent;
134
- updateProps(oldProps: TextTagProps | null, newProps: TextTagProps): void;
135
- unmount(): void;
136
36
  }
37
+ export {};