@gtkx/react 0.15.0 → 0.17.1

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 (172) hide show
  1. package/README.md +1 -0
  2. package/dist/animation/css-builder.d.ts +3 -0
  3. package/dist/animation/css-builder.js +53 -0
  4. package/dist/animation/types.d.ts +120 -0
  5. package/dist/errors.js +3 -0
  6. package/dist/factory.d.ts +3 -2
  7. package/dist/factory.js +1 -1
  8. package/dist/fiber-root.js +1 -1
  9. package/dist/generated/internal.d.ts +28 -1
  10. package/dist/generated/internal.js +93 -18
  11. package/dist/generated/jsx.d.ts +1672 -1483
  12. package/dist/generated/jsx.js +475 -0
  13. package/dist/host-config.d.ts +3 -1
  14. package/dist/host-config.js +26 -11
  15. package/dist/jsx.d.ts +136 -166
  16. package/dist/jsx.js +58 -69
  17. package/dist/node.d.ts +4 -1
  18. package/dist/node.js +14 -3
  19. package/dist/nodes/abstract/positional-child.d.ts +9 -0
  20. package/dist/nodes/abstract/positional-child.js +29 -0
  21. package/dist/nodes/abstract/virtual-container.d.ts +21 -0
  22. package/dist/nodes/abstract/virtual-container.js +68 -0
  23. package/dist/nodes/abstract/virtual-single-child.d.ts +18 -0
  24. package/dist/nodes/abstract/virtual-single-child.js +55 -0
  25. package/dist/nodes/action-row-child.d.ts +0 -13
  26. package/dist/nodes/action-row-child.js +22 -12
  27. package/dist/nodes/adjustable.d.ts +23 -0
  28. package/dist/nodes/adjustable.js +62 -0
  29. package/dist/nodes/alert-dialog-response.js +86 -0
  30. package/dist/nodes/animation.js +252 -0
  31. package/dist/nodes/application.js +17 -7
  32. package/dist/nodes/autowrapped.js +37 -43
  33. package/dist/nodes/calendar.js +17 -43
  34. package/dist/nodes/color-dialog-button.d.ts +1 -0
  35. package/dist/nodes/color-dialog-button.js +70 -0
  36. package/dist/nodes/column-view-column.d.ts +3 -3
  37. package/dist/nodes/column-view-column.js +1 -1
  38. package/dist/nodes/column-view.js +36 -39
  39. package/dist/nodes/dialog.d.ts +11 -0
  40. package/dist/nodes/dialog.js +20 -0
  41. package/dist/nodes/drawing-area.js +24 -7
  42. package/dist/nodes/event-controller.d.ts +22 -0
  43. package/dist/nodes/event-controller.js +96 -0
  44. package/dist/nodes/expander-row-child.d.ts +0 -14
  45. package/dist/nodes/expander-row-child.js +22 -12
  46. package/dist/nodes/fixed-child.js +52 -36
  47. package/dist/nodes/font-dialog-button.d.ts +1 -0
  48. package/dist/nodes/font-dialog-button.js +90 -0
  49. package/dist/nodes/grid-child.js +43 -45
  50. package/dist/nodes/grid.d.ts +1 -0
  51. package/dist/nodes/grid.js +41 -0
  52. package/dist/nodes/index.d.ts +18 -12
  53. package/dist/nodes/index.js +18 -12
  54. package/dist/nodes/internal/base-item-renderer.d.ts +29 -0
  55. package/dist/nodes/internal/base-item-renderer.js +88 -0
  56. package/dist/nodes/internal/child-attachment.d.ts +26 -0
  57. package/dist/nodes/internal/child-attachment.js +48 -0
  58. package/dist/nodes/internal/deferred-action.d.ts +9 -0
  59. package/dist/nodes/internal/deferred-action.js +22 -0
  60. package/dist/nodes/internal/list-item-renderer.d.ts +14 -15
  61. package/dist/nodes/internal/list-item-renderer.js +51 -77
  62. package/dist/nodes/internal/list-store.d.ts +5 -6
  63. package/dist/nodes/internal/list-store.js +29 -38
  64. package/dist/nodes/internal/predicates.d.ts +25 -2
  65. package/dist/nodes/internal/predicates.js +53 -41
  66. package/dist/nodes/internal/selection-model.d.ts +30 -0
  67. package/dist/nodes/internal/selection-model.js +87 -0
  68. package/dist/nodes/internal/signal-store.d.ts +9 -5
  69. package/dist/nodes/internal/signal-store.js +31 -31
  70. package/dist/nodes/internal/simple-list-store.js +6 -9
  71. package/dist/nodes/internal/text-buffer-controller.d.ts +43 -0
  72. package/dist/nodes/internal/text-buffer-controller.js +287 -0
  73. package/dist/nodes/internal/text-tag-styles.d.ts +43 -0
  74. package/dist/nodes/internal/text-tag-styles.js +52 -0
  75. package/dist/nodes/internal/tree-list-item-renderer.d.ts +15 -14
  76. package/dist/nodes/internal/tree-list-item-renderer.js +85 -96
  77. package/dist/nodes/internal/tree-store.d.ts +8 -11
  78. package/dist/nodes/internal/tree-store.js +70 -72
  79. package/dist/nodes/internal/utils.d.ts +7 -4
  80. package/dist/nodes/internal/utils.js +50 -5
  81. package/dist/nodes/level-bar.js +19 -54
  82. package/dist/nodes/list-item.d.ts +6 -3
  83. package/dist/nodes/list-item.js +7 -4
  84. package/dist/nodes/list-view.js +17 -12
  85. package/dist/nodes/menu.d.ts +3 -3
  86. package/dist/nodes/menu.js +3 -3
  87. package/dist/nodes/models/list.d.ts +11 -13
  88. package/dist/nodes/models/list.js +16 -73
  89. package/dist/nodes/models/menu.d.ts +8 -7
  90. package/dist/nodes/models/menu.js +43 -50
  91. package/dist/nodes/models/tree-list.d.ts +6 -12
  92. package/dist/nodes/models/tree-list.js +30 -93
  93. package/dist/nodes/navigation-page.d.ts +1 -0
  94. package/dist/nodes/navigation-page.js +27 -32
  95. package/dist/nodes/navigation-view.js +17 -28
  96. package/dist/nodes/notebook-page-tab.d.ts +3 -3
  97. package/dist/nodes/notebook-page-tab.js +11 -14
  98. package/dist/nodes/notebook-page.d.ts +7 -5
  99. package/dist/nodes/notebook-page.js +45 -25
  100. package/dist/nodes/notebook.js +2 -2
  101. package/dist/nodes/overlay-child.js +90 -30
  102. package/dist/nodes/pack-child.d.ts +0 -13
  103. package/dist/nodes/pack-child.js +22 -12
  104. package/dist/nodes/popover-menu.js +2 -2
  105. package/dist/nodes/scale.js +15 -45
  106. package/dist/nodes/scrolled-window.js +7 -6
  107. package/dist/nodes/search-bar.d.ts +1 -0
  108. package/dist/nodes/search-bar.js +40 -0
  109. package/dist/nodes/shortcut-controller.d.ts +1 -37
  110. package/dist/nodes/shortcut-controller.js +8 -47
  111. package/dist/nodes/shortcut.d.ts +5 -4
  112. package/dist/nodes/shortcut.js +11 -5
  113. package/dist/nodes/simple-list-view.js +2 -3
  114. package/dist/nodes/slot.d.ts +6 -9
  115. package/dist/nodes/slot.js +27 -42
  116. package/dist/nodes/source-view.js +80 -29
  117. package/dist/nodes/stack-page.js +20 -22
  118. package/dist/nodes/stack.js +19 -5
  119. package/dist/nodes/text-anchor.d.ts +41 -0
  120. package/dist/nodes/text-anchor.js +59 -0
  121. package/dist/nodes/text-content.d.ts +10 -0
  122. package/dist/nodes/text-content.js +1 -0
  123. package/dist/nodes/text-paintable.d.ts +17 -0
  124. package/dist/nodes/text-paintable.js +34 -0
  125. package/dist/nodes/text-segment.d.ts +15 -0
  126. package/dist/nodes/text-segment.js +29 -0
  127. package/dist/nodes/text-tag.d.ts +136 -0
  128. package/dist/nodes/text-tag.js +202 -0
  129. package/dist/nodes/text-view.d.ts +30 -0
  130. package/dist/nodes/text-view.js +49 -21
  131. package/dist/nodes/toggle-group.js +24 -32
  132. package/dist/nodes/toggle.d.ts +1 -15
  133. package/dist/nodes/toggle.js +40 -32
  134. package/dist/nodes/toolbar-child.js +22 -31
  135. package/dist/nodes/tree-list-item.d.ts +7 -5
  136. package/dist/nodes/tree-list-item.js +24 -36
  137. package/dist/nodes/tree-list-view.js +9 -7
  138. package/dist/nodes/virtual.d.ts +1 -1
  139. package/dist/nodes/web-view.d.ts +1 -0
  140. package/dist/nodes/web-view.js +29 -0
  141. package/dist/nodes/widget.d.ts +2 -16
  142. package/dist/nodes/widget.js +105 -294
  143. package/dist/nodes/window.d.ts +9 -3
  144. package/dist/nodes/window.js +29 -15
  145. package/dist/registry.d.ts +1 -1
  146. package/dist/render.js +9 -7
  147. package/dist/scheduler.d.ts +11 -1
  148. package/dist/scheduler.js +16 -4
  149. package/dist/types.d.ts +2 -136
  150. package/package.json +4 -4
  151. package/dist/nodes/action-row.js +0 -46
  152. package/dist/nodes/adjustment.d.ts +0 -48
  153. package/dist/nodes/adjustment.js +0 -70
  154. package/dist/nodes/calendar-mark.d.ts +0 -15
  155. package/dist/nodes/calendar-mark.js +0 -29
  156. package/dist/nodes/expander-row.js +0 -55
  157. package/dist/nodes/internal/constants.d.ts +0 -1
  158. package/dist/nodes/internal/constants.js +0 -24
  159. package/dist/nodes/level-bar-offset.d.ts +0 -13
  160. package/dist/nodes/level-bar-offset.js +0 -35
  161. package/dist/nodes/pack.js +0 -46
  162. package/dist/nodes/scale-mark.d.ts +0 -17
  163. package/dist/nodes/scale-mark.js +0 -38
  164. package/dist/nodes/source-buffer.d.ts +0 -73
  165. package/dist/nodes/source-buffer.js +0 -149
  166. package/dist/nodes/text-buffer.d.ts +0 -43
  167. package/dist/nodes/text-buffer.js +0 -81
  168. package/dist/nodes/virtual-child.d.ts +0 -18
  169. package/dist/nodes/virtual-child.js +0 -62
  170. /package/dist/{nodes/action-row.d.ts → animation/types.js} +0 -0
  171. /package/dist/nodes/{expander-row.d.ts → alert-dialog-response.d.ts} +0 -0
  172. /package/dist/nodes/{pack.d.ts → animation.d.ts} +0 -0
@@ -1,38 +1,44 @@
1
1
  import { isObjectEqual } from "@gtkx/ffi";
2
2
  import { toCamelCase } from "@gtkx/gir";
3
3
  import { registerNodeClass } from "../registry.js";
4
- import { CommitPriority, scheduleAfterCommit } from "../scheduler.js";
4
+ import { VirtualSingleChildNode } from "./abstract/virtual-single-child.js";
5
5
  import { resolvePropMeta } from "./internal/utils.js";
6
- import { VirtualNode } from "./virtual.js";
7
- import { WidgetNode } from "./widget.js";
8
- export class SlotNode extends VirtualNode {
6
+ export class SlotNode extends VirtualSingleChildNode {
9
7
  static priority = 2;
10
8
  static matches(type) {
11
9
  return type === "Slot";
12
10
  }
13
- parent;
14
- child;
11
+ cachedSetter = null;
15
12
  setParent(parent) {
16
- this.parent = parent;
13
+ if (!isObjectEqual(this.parent, parent)) {
14
+ this.cachedSetter = null;
15
+ }
16
+ super.setParent(parent);
17
17
  }
18
18
  unmount() {
19
19
  if (this.parent && this.child) {
20
20
  const parent = this.parent;
21
21
  const oldChild = this.child;
22
- this.child = undefined;
22
+ this.child = null;
23
23
  queueMicrotask(() => {
24
24
  if (parent.getRoot() !== null) {
25
25
  this.parent = parent;
26
26
  this.onChildChange(oldChild);
27
27
  }
28
- this.parent = undefined;
28
+ this.parent = null;
29
29
  });
30
30
  }
31
31
  else {
32
- this.parent = undefined;
32
+ this.parent = null;
33
33
  }
34
34
  super.unmount();
35
35
  }
36
+ getChild() {
37
+ if (!this.child) {
38
+ throw new Error(`Expected child widget to be set on '${this.getId()}' SlotNode`);
39
+ }
40
+ return this.child;
41
+ }
36
42
  getId() {
37
43
  const id = this.props.id;
38
44
  if (!id) {
@@ -46,55 +52,34 @@ export class SlotNode extends VirtualNode {
46
52
  }
47
53
  return this.parent;
48
54
  }
49
- getChild() {
50
- if (!this.child) {
51
- throw new Error(`Expected child widget to be set on '${this.getId()}' SlotNode`);
52
- }
53
- return this.child;
54
- }
55
- appendChild(child) {
56
- if (!(child instanceof WidgetNode)) {
57
- throw new Error(`Cannot append '${child.typeName}' to 'Slot': expected Widget`);
58
- }
59
- const oldChild = this.child;
60
- this.child = child.container;
61
- scheduleAfterCommit(() => {
62
- if (this.parent) {
63
- this.onChildChange(oldChild ?? null);
64
- }
65
- });
66
- }
67
- removeChild() {
68
- const oldChild = this.child;
69
- scheduleAfterCommit(() => {
70
- if (oldChild === this.child) {
71
- this.child = undefined;
72
- }
73
- if (this.parent) {
74
- this.onChildChange(oldChild ?? null);
75
- }
76
- }, CommitPriority.HIGH);
77
- }
78
- onChildChange(oldChild) {
55
+ ensureChildSetter() {
56
+ if (this.cachedSetter)
57
+ return this.cachedSetter;
79
58
  const parent = this.getParent();
80
59
  const parentType = parent.constructor.glibTypeName;
81
60
  const propMeta = resolvePropMeta(parent, this.getId());
82
61
  if (!propMeta) {
83
62
  throw new Error(`Unable to find property for Slot '${this.getId()}' on type '${parentType}'`);
84
63
  }
85
- const [_, setterName] = propMeta;
64
+ const [, setterName] = propMeta;
86
65
  const setter = parent[setterName];
87
66
  if (typeof setter !== "function") {
88
67
  throw new Error(`Expected setter function for Slot '${this.getId()}' on type '${parentType}'`);
89
68
  }
69
+ this.cachedSetter = setter.bind(parent);
70
+ return this.cachedSetter;
71
+ }
72
+ onChildChange(oldChild) {
73
+ const setter = this.ensureChildSetter();
90
74
  if (oldChild && !this.child) {
75
+ const parent = this.getParent();
91
76
  const root = oldChild.getRoot();
92
77
  const focusWidget = root?.getFocus?.();
93
78
  if (focusWidget && this.isDescendantOf(focusWidget, oldChild)) {
94
79
  parent.grabFocus();
95
80
  }
96
81
  }
97
- setter.call(parent, this.child);
82
+ setter(this.child);
98
83
  }
99
84
  isDescendantOf(widget, ancestor) {
100
85
  let current = widget;
@@ -1,42 +1,93 @@
1
1
  import * as GtkSource from "@gtkx/ffi/gtksource";
2
2
  import { registerNodeClass } from "../registry.js";
3
- import { isContainerType } from "./internal/utils.js";
4
- import { SourceBufferNode } from "./source-buffer.js";
5
- import { WidgetNode } from "./widget.js";
6
- class SourceViewNode extends WidgetNode {
3
+ import { TextBufferController } from "./internal/text-buffer-controller.js";
4
+ import { hasChanged, matchesAnyClass } from "./internal/utils.js";
5
+ import { TextViewNode } from "./text-view.js";
6
+ class SourceViewNode extends TextViewNode {
7
7
  static priority = 1;
8
- bufferChild;
9
8
  static matches(_type, containerOrClass) {
10
- return isContainerType(GtkSource.View, containerOrClass);
9
+ return matchesAnyClass([GtkSource.View], containerOrClass);
11
10
  }
12
- appendChild(child) {
13
- if (this.tryAttachSourceBuffer(child))
14
- return;
15
- super.appendChild(child);
11
+ createBufferController() {
12
+ return new TextBufferController(this, this.container, () => new GtkSource.Buffer());
16
13
  }
17
- insertBefore(child, before) {
18
- if (this.tryAttachSourceBuffer(child))
19
- return;
20
- super.insertBefore(child, before);
14
+ ensureBufferController() {
15
+ return super.ensureBufferController();
21
16
  }
22
- removeChild(child) {
23
- if (child instanceof SourceBufferNode) {
24
- if (this.bufferChild === child) {
25
- this.bufferChild = undefined;
26
- }
27
- return;
17
+ applyOwnProps(oldProps, newProps) {
18
+ super.applyOwnProps(oldProps, newProps);
19
+ this.applySourceViewProps(oldProps, newProps);
20
+ }
21
+ resolveLanguage(language) {
22
+ if (typeof language === "string") {
23
+ const langManager = GtkSource.LanguageManager.getDefault();
24
+ return langManager.getLanguage(language);
28
25
  }
29
- super.removeChild(child);
26
+ return language;
30
27
  }
31
- tryAttachSourceBuffer(child) {
32
- if (!(child instanceof SourceBufferNode))
33
- return false;
34
- if (this.bufferChild) {
35
- throw new Error("SourceView can only have one SourceBuffer child");
28
+ resolveStyleScheme(scheme) {
29
+ if (typeof scheme === "string") {
30
+ const schemeManager = GtkSource.StyleSchemeManager.getDefault();
31
+ return schemeManager.getScheme(scheme);
32
+ }
33
+ return scheme;
34
+ }
35
+ applySourceViewProps(oldProps, newProps) {
36
+ const hasSourceViewProps = newProps.language !== undefined ||
37
+ newProps.styleScheme !== undefined ||
38
+ newProps.highlightSyntax !== undefined ||
39
+ newProps.highlightMatchingBrackets !== undefined ||
40
+ newProps.implicitTrailingNewline !== undefined ||
41
+ newProps.onCursorMoved !== undefined ||
42
+ newProps.onHighlightUpdated !== undefined ||
43
+ oldProps?.language !== undefined ||
44
+ oldProps?.styleScheme !== undefined;
45
+ if (!hasSourceViewProps) {
46
+ return;
47
+ }
48
+ const buffer = this.ensureBufferController().ensureBuffer();
49
+ if (hasChanged(oldProps, newProps, "language")) {
50
+ if (newProps.language !== undefined) {
51
+ const language = this.resolveLanguage(newProps.language);
52
+ buffer.setLanguage(language);
53
+ }
54
+ else if (oldProps?.language !== undefined) {
55
+ buffer.setLanguage(null);
56
+ }
36
57
  }
37
- this.bufferChild = child;
38
- child.setSourceView(this.container);
39
- return true;
58
+ if (hasChanged(oldProps, newProps, "styleScheme")) {
59
+ if (newProps.styleScheme !== undefined) {
60
+ const scheme = this.resolveStyleScheme(newProps.styleScheme);
61
+ buffer.setStyleScheme(scheme);
62
+ }
63
+ else if (oldProps?.styleScheme !== undefined) {
64
+ buffer.setStyleScheme(null);
65
+ }
66
+ }
67
+ if (hasChanged(oldProps, newProps, "highlightSyntax") || hasChanged(oldProps, newProps, "language")) {
68
+ const highlightSyntax = newProps.highlightSyntax ?? newProps.language !== undefined;
69
+ buffer.setHighlightSyntax(highlightSyntax);
70
+ }
71
+ if (hasChanged(oldProps, newProps, "highlightMatchingBrackets")) {
72
+ const highlightMatchingBrackets = newProps.highlightMatchingBrackets ?? true;
73
+ buffer.setHighlightMatchingBrackets(highlightMatchingBrackets);
74
+ }
75
+ if (hasChanged(oldProps, newProps, "implicitTrailingNewline")) {
76
+ if (newProps.implicitTrailingNewline !== undefined) {
77
+ buffer.setImplicitTrailingNewline(newProps.implicitTrailingNewline);
78
+ }
79
+ }
80
+ if (hasChanged(oldProps, newProps, "onCursorMoved") || hasChanged(oldProps, newProps, "onHighlightUpdated")) {
81
+ this.updateSourceViewSignalHandlers(newProps);
82
+ }
83
+ }
84
+ updateSourceViewSignalHandlers(props) {
85
+ const buffer = this.ensureBufferController().getBuffer();
86
+ if (!buffer)
87
+ return;
88
+ const { onCursorMoved, onHighlightUpdated } = props;
89
+ this.signalStore.set(this, buffer, "cursor-moved", onCursorMoved ?? null);
90
+ this.signalStore.set(this, buffer, "highlight-updated", onHighlightUpdated ? (start, end) => onHighlightUpdated(start, end) : null);
40
91
  }
41
92
  }
42
93
  registerNodeClass(SourceViewNode);
@@ -1,41 +1,47 @@
1
- import { batch, isObjectEqual } from "@gtkx/ffi";
1
+ import { isObjectEqual } from "@gtkx/ffi";
2
2
  import * as Adw from "@gtkx/ffi/adw";
3
3
  import { registerNodeClass } from "../registry.js";
4
+ import { hasChanged } from "./internal/utils.js";
4
5
  import { SlotNode } from "./slot.js";
5
6
  class StackPageNode extends SlotNode {
6
7
  static priority = 1;
7
- page;
8
+ page = null;
8
9
  static matches(type) {
9
10
  return type === "StackPage";
10
11
  }
11
12
  updateProps(oldProps, newProps) {
12
13
  super.updateProps(oldProps, newProps);
14
+ this.applyOwnProps(oldProps, newProps);
15
+ }
16
+ applyOwnProps(oldProps, newProps) {
13
17
  if (!this.page) {
14
18
  return;
15
19
  }
16
- if (!oldProps || oldProps.title !== newProps.title) {
17
- if (newProps.title !== undefined) {
18
- this.page.setTitle(newProps.title);
19
- }
20
+ if (hasChanged(oldProps, newProps, "title") && newProps.title !== undefined) {
21
+ this.page.setTitle(newProps.title);
20
22
  }
21
- if (!oldProps || oldProps.iconName !== newProps.iconName) {
22
- if (newProps.iconName !== undefined) {
23
- this.page.setIconName(newProps.iconName);
24
- }
23
+ if (hasChanged(oldProps, newProps, "iconName") && newProps.iconName !== undefined) {
24
+ this.page.setIconName(newProps.iconName);
25
25
  }
26
- if (!oldProps || oldProps.needsAttention !== newProps.needsAttention) {
26
+ if (hasChanged(oldProps, newProps, "needsAttention")) {
27
27
  this.page.setNeedsAttention(newProps.needsAttention ?? false);
28
28
  }
29
- if (!oldProps || oldProps.visible !== newProps.visible) {
29
+ if (hasChanged(oldProps, newProps, "visible")) {
30
30
  this.page.setVisible(newProps.visible ?? true);
31
31
  }
32
- if (!oldProps || oldProps.useUnderline !== newProps.useUnderline) {
32
+ if (hasChanged(oldProps, newProps, "useUnderline")) {
33
33
  this.page.setUseUnderline(newProps.useUnderline ?? false);
34
34
  }
35
- if ("setBadgeNumber" in this.page && (!oldProps || oldProps.badgeNumber !== newProps.badgeNumber)) {
35
+ if ("setBadgeNumber" in this.page && hasChanged(oldProps, newProps, "badgeNumber")) {
36
36
  this.page.setBadgeNumber?.(newProps.badgeNumber ?? 0);
37
37
  }
38
38
  }
39
+ onChildChange(oldChild) {
40
+ this.removePage(oldChild);
41
+ if (this.child) {
42
+ this.addPage();
43
+ }
44
+ }
39
45
  addPage() {
40
46
  const child = this.getChild();
41
47
  const parent = this.getParent();
@@ -78,13 +84,5 @@ class StackPageNode extends SlotNode {
78
84
  parent.remove(oldChild);
79
85
  }
80
86
  }
81
- onChildChange(oldChild) {
82
- batch(() => {
83
- this.removePage(oldChild);
84
- if (this.child) {
85
- this.addPage();
86
- }
87
- });
88
- }
89
87
  }
90
88
  registerNodeClass(StackPageNode);
@@ -1,24 +1,38 @@
1
1
  import { STACK_CLASSES } from "../generated/internal.js";
2
2
  import { registerNodeClass } from "../registry.js";
3
- import { scheduleAfterCommit } from "../scheduler.js";
4
- import { filterProps, matchesAnyClass } from "./internal/utils.js";
3
+ import { CommitPriority, scheduleAfterCommit } from "../scheduler.js";
4
+ import { filterProps, hasChanged, matchesAnyClass } from "./internal/utils.js";
5
5
  import { WidgetNode } from "./widget.js";
6
- const PROPS = ["page"];
6
+ const OWN_PROPS = ["page", "onPageChanged"];
7
7
  class StackNode extends WidgetNode {
8
8
  static priority = 1;
9
9
  static matches(_type, containerOrClass) {
10
10
  return matchesAnyClass(STACK_CLASSES, containerOrClass);
11
11
  }
12
12
  updateProps(oldProps, newProps) {
13
+ super.updateProps(oldProps ? filterProps(oldProps, OWN_PROPS) : null, filterProps(newProps, OWN_PROPS));
14
+ this.applyOwnProps(oldProps, newProps);
15
+ }
16
+ applyOwnProps(oldProps, newProps) {
13
17
  if (newProps.page && this.container.getVisibleChildName() !== newProps.page) {
14
18
  const page = newProps.page;
15
19
  scheduleAfterCommit(() => {
16
20
  if (this.container.getChildByName(page)) {
17
21
  this.container.setVisibleChildName(page);
18
22
  }
19
- });
23
+ }, CommitPriority.NORMAL);
24
+ }
25
+ if (hasChanged(oldProps, newProps, "onPageChanged")) {
26
+ 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
+ }
20
35
  }
21
- super.updateProps(filterProps(oldProps ?? {}, PROPS), filterProps(newProps, PROPS));
22
36
  }
23
37
  }
24
38
  registerNodeClass(StackNode);
@@ -0,0 +1,41 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { ReactNode } from "react";
3
+ import type { Node } from "../node.js";
4
+ 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;
28
+ private textView;
29
+ private buffer;
30
+ private anchor;
31
+ private widgetChild;
32
+ bufferOffset: number;
33
+ static matches(type: string): boolean;
34
+ getLength(): number;
35
+ getText(): string;
36
+ setTextViewAndBuffer(textView: Gtk.TextView, buffer: Gtk.TextBuffer): void;
37
+ private setupAnchor;
38
+ appendChild(child: Node): void;
39
+ removeChild(child: Node): void;
40
+ unmount(): void;
41
+ }
@@ -0,0 +1,59 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { VirtualNode } from "./virtual.js";
4
+ import { WidgetNode } from "./widget.js";
5
+ const PLACEHOLDER = "\uFFFC";
6
+ export class TextAnchorNode extends VirtualNode {
7
+ static priority = 1;
8
+ textView = null;
9
+ buffer = null;
10
+ anchor = null;
11
+ widgetChild = null;
12
+ bufferOffset = 0;
13
+ static matches(type) {
14
+ return type === "TextAnchor";
15
+ }
16
+ getLength() {
17
+ return 1;
18
+ }
19
+ getText() {
20
+ return PLACEHOLDER;
21
+ }
22
+ setTextViewAndBuffer(textView, buffer) {
23
+ this.textView = textView;
24
+ this.buffer = buffer;
25
+ this.setupAnchor();
26
+ }
27
+ setupAnchor() {
28
+ if (!this.textView || !this.buffer)
29
+ return;
30
+ const iter = new Gtk.TextIter();
31
+ this.buffer.getIterAtOffset(iter, this.bufferOffset);
32
+ this.anchor = this.buffer.createChildAnchor(iter);
33
+ if (this.widgetChild?.container && this.anchor) {
34
+ this.textView.addChildAtAnchor(this.widgetChild.container, this.anchor);
35
+ }
36
+ }
37
+ 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;
42
+ if (this.textView && this.anchor && child.container) {
43
+ this.textView.addChildAtAnchor(child.container, this.anchor);
44
+ }
45
+ }
46
+ removeChild(child) {
47
+ if (child === this.widgetChild) {
48
+ this.widgetChild = null;
49
+ }
50
+ }
51
+ unmount() {
52
+ this.anchor = null;
53
+ this.widgetChild = null;
54
+ this.buffer = null;
55
+ this.textView = null;
56
+ super.unmount();
57
+ }
58
+ }
59
+ registerNodeClass(TextAnchorNode);
@@ -0,0 +1,10 @@
1
+ import type { TextAnchorNode } from "./text-anchor.js";
2
+ import type { TextPaintableNode } from "./text-paintable.js";
3
+ import type { TextSegmentNode } from "./text-segment.js";
4
+ import type { TextTagNode } from "./text-tag.js";
5
+ export type TextContentChild = TextSegmentNode | TextTagNode | TextAnchorNode | TextPaintableNode;
6
+ export type TextContentParent = {
7
+ onChildInserted(child: TextContentChild): void;
8
+ onChildRemoved(child: TextContentChild): void;
9
+ onChildTextChanged(child: TextSegmentNode, oldLength: number, newLength: number): void;
10
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import type * as Gdk from "@gtkx/ffi/gdk";
2
+ import * as Gtk from "@gtkx/ffi/gtk";
3
+ import { VirtualNode } from "./virtual.js";
4
+ export type TextPaintableProps = {
5
+ paintable: Gdk.Paintable;
6
+ };
7
+ export declare class TextPaintableNode extends VirtualNode<TextPaintableProps> {
8
+ static priority: number;
9
+ private buffer;
10
+ bufferOffset: number;
11
+ static matches(type: string): boolean;
12
+ getLength(): number;
13
+ getText(): string;
14
+ setTextViewAndBuffer(_textView: Gtk.TextView, buffer: Gtk.TextBuffer): void;
15
+ private insertPaintable;
16
+ unmount(): void;
17
+ }
@@ -0,0 +1,34 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { VirtualNode } from "./virtual.js";
4
+ const PLACEHOLDER = "\uFFFC";
5
+ export class TextPaintableNode extends VirtualNode {
6
+ static priority = 1;
7
+ buffer = null;
8
+ bufferOffset = 0;
9
+ static matches(type) {
10
+ return type === "TextPaintable";
11
+ }
12
+ getLength() {
13
+ return 1;
14
+ }
15
+ getText() {
16
+ return PLACEHOLDER;
17
+ }
18
+ setTextViewAndBuffer(_textView, buffer) {
19
+ this.buffer = buffer;
20
+ this.insertPaintable();
21
+ }
22
+ insertPaintable() {
23
+ if (!this.buffer || !this.props.paintable)
24
+ return;
25
+ const iter = new Gtk.TextIter();
26
+ this.buffer.getIterAtOffset(iter, this.bufferOffset);
27
+ this.buffer.insertPaintable(iter, this.props.paintable);
28
+ }
29
+ unmount() {
30
+ this.buffer = null;
31
+ super.unmount();
32
+ }
33
+ }
34
+ registerNodeClass(TextPaintableNode);
@@ -0,0 +1,15 @@
1
+ import type { TextContentParent } from "./text-content.js";
2
+ 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;
12
+ getText(): string;
13
+ getLength(): number;
14
+ updateProps(oldProps: TextSegmentProps | null, newProps: TextSegmentProps): void;
15
+ }
@@ -0,0 +1,29 @@
1
+ import { registerNodeClass } from "../registry.js";
2
+ import { hasChanged } from "./internal/utils.js";
3
+ import { VirtualNode } from "./virtual.js";
4
+ export class TextSegmentNode extends VirtualNode {
5
+ static priority = 1;
6
+ parent = null;
7
+ bufferOffset = 0;
8
+ static matches(type) {
9
+ return type === "TextSegment";
10
+ }
11
+ setParent(parent) {
12
+ this.parent = parent;
13
+ }
14
+ getText() {
15
+ return this.props.text;
16
+ }
17
+ getLength() {
18
+ return this.props.text.length;
19
+ }
20
+ updateProps(oldProps, newProps) {
21
+ const oldText = oldProps?.text ?? "";
22
+ const newText = newProps.text;
23
+ super.updateProps(oldProps, newProps);
24
+ if (hasChanged(oldProps, newProps, "text") && this.parent) {
25
+ this.parent.onChildTextChanged(this, oldText.length, newText.length);
26
+ }
27
+ }
28
+ }
29
+ registerNodeClass(TextSegmentNode);