@gtkx/react 0.13.3 → 0.15.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/README.md +8 -7
- package/dist/generated/internal.js +98 -0
- package/dist/generated/jsx.d.ts +908 -1572
- package/dist/host-config.js +2 -2
- package/dist/jsx.d.ts +176 -36
- package/dist/jsx.js +96 -5
- package/dist/nodes/adjustment.d.ts +48 -0
- package/dist/nodes/adjustment.js +70 -0
- package/dist/nodes/application.js +6 -6
- package/dist/nodes/calendar.js +3 -16
- package/dist/nodes/column-view-column.d.ts +1 -0
- package/dist/nodes/column-view-column.js +4 -0
- package/dist/nodes/column-view.js +6 -6
- package/dist/nodes/drawing-area.d.ts +1 -0
- package/dist/nodes/drawing-area.js +19 -0
- package/dist/nodes/expander-row.js +1 -0
- package/dist/nodes/index.d.ts +9 -0
- package/dist/nodes/index.js +9 -0
- package/dist/nodes/internal/constants.js +14 -0
- package/dist/nodes/internal/list-item-renderer.d.ts +1 -0
- package/dist/nodes/internal/list-item-renderer.js +6 -1
- package/dist/nodes/internal/predicates.d.ts +4 -0
- package/dist/nodes/internal/predicates.js +3 -0
- package/dist/nodes/internal/signal-store.d.ts +1 -0
- package/dist/nodes/internal/signal-store.js +7 -0
- package/dist/nodes/internal/tree-list-item-renderer.d.ts +1 -0
- package/dist/nodes/internal/tree-list-item-renderer.js +9 -1
- package/dist/nodes/level-bar.js +3 -16
- package/dist/nodes/list-view.js +11 -2
- package/dist/nodes/models/list.d.ts +6 -1
- package/dist/nodes/models/list.js +21 -6
- package/dist/nodes/models/tree-list.d.ts +6 -1
- package/dist/nodes/models/tree-list.js +21 -7
- package/dist/nodes/navigation-page.js +32 -23
- package/dist/nodes/notebook-page-tab.d.ts +1 -0
- package/dist/nodes/notebook-page-tab.js +15 -9
- package/dist/nodes/notebook-page.js +9 -6
- package/dist/nodes/scale.js +3 -16
- package/dist/nodes/scrolled-window.d.ts +1 -0
- package/dist/nodes/scrolled-window.js +22 -0
- package/dist/nodes/shortcut-controller.d.ts +37 -0
- package/dist/nodes/shortcut-controller.js +74 -0
- package/dist/nodes/shortcut.d.ts +38 -0
- package/dist/nodes/shortcut.js +46 -0
- package/dist/nodes/slot.js +11 -2
- package/dist/nodes/source-buffer.d.ts +73 -0
- package/dist/nodes/source-buffer.js +149 -0
- package/dist/nodes/source-view.d.ts +1 -0
- package/dist/nodes/source-view.js +42 -0
- package/dist/nodes/stack-page.js +15 -9
- package/dist/nodes/text-buffer.d.ts +43 -0
- package/dist/nodes/text-buffer.js +81 -0
- package/dist/nodes/text-view.d.ts +1 -0
- package/dist/nodes/text-view.js +45 -0
- package/dist/nodes/tree-list-view.js +11 -2
- package/dist/nodes/widget.d.ts +9 -0
- package/dist/nodes/widget.js +166 -13
- package/dist/nodes/window.js +7 -5
- package/dist/render.d.ts +14 -14
- package/dist/render.js +14 -14
- package/dist/types.d.ts +110 -1
- package/package.json +3 -3
|
@@ -8,6 +8,7 @@ export declare class NotebookPageTabNode extends SlotNode<Props> {
|
|
|
8
8
|
private page?;
|
|
9
9
|
static matches(type: string): boolean;
|
|
10
10
|
setPage(notebook?: Gtk.Notebook, page?: Gtk.Widget): void;
|
|
11
|
+
updateProps(oldProps: Props | null, newProps: Props): void;
|
|
11
12
|
private getNotebook;
|
|
12
13
|
private getPage;
|
|
13
14
|
protected onChildChange(_oldChild: Gtk.Widget | null): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { batch } from "@gtkx/ffi";
|
|
1
2
|
import { registerNodeClass } from "../registry.js";
|
|
2
3
|
import { SlotNode } from "./slot.js";
|
|
3
4
|
export class NotebookPageTabNode extends SlotNode {
|
|
@@ -12,6 +13,9 @@ export class NotebookPageTabNode extends SlotNode {
|
|
|
12
13
|
this.page = page;
|
|
13
14
|
this.setParent(notebook);
|
|
14
15
|
}
|
|
16
|
+
updateProps(oldProps, newProps) {
|
|
17
|
+
super.updateProps(oldProps, newProps);
|
|
18
|
+
}
|
|
15
19
|
getNotebook() {
|
|
16
20
|
if (!this.notebook) {
|
|
17
21
|
throw new Error("Expected Notebook reference to be set on NotebookPageTabNode");
|
|
@@ -25,15 +29,17 @@ export class NotebookPageTabNode extends SlotNode {
|
|
|
25
29
|
return this.page;
|
|
26
30
|
}
|
|
27
31
|
onChildChange(_oldChild) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
batch(() => {
|
|
33
|
+
if (!this.notebook || !this.page) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const notebook = this.getNotebook();
|
|
37
|
+
const page = this.getPage();
|
|
38
|
+
if (notebook.pageNum(page) === -1) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
notebook.setTabLabel(page, this.child);
|
|
42
|
+
});
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
registerNodeClass(NotebookPageTabNode);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { batch } from "@gtkx/ffi";
|
|
1
2
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
3
|
import { registerNodeClass } from "../registry.js";
|
|
3
4
|
import { scheduleAfterCommit } from "../scheduler.js";
|
|
@@ -93,12 +94,14 @@ export class NotebookPageNode extends SlotNode {
|
|
|
93
94
|
notebook.removePage(pageNum);
|
|
94
95
|
}
|
|
95
96
|
onChildChange(oldChild) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
|
|
97
|
+
batch(() => {
|
|
98
|
+
if (oldChild) {
|
|
99
|
+
this.detachPage(oldChild);
|
|
100
|
+
}
|
|
101
|
+
if (this.child) {
|
|
102
|
+
this.attachPage();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
registerNodeClass(NotebookPageNode);
|
package/dist/nodes/scale.js
CHANGED
|
@@ -3,7 +3,6 @@ import { registerNodeClass } from "../registry.js";
|
|
|
3
3
|
import { CommitPriority, scheduleAfterCommit } from "../scheduler.js";
|
|
4
4
|
import { isContainerType } from "./internal/utils.js";
|
|
5
5
|
import { ScaleMarkNode } from "./scale-mark.js";
|
|
6
|
-
import { SlotNode } from "./slot.js";
|
|
7
6
|
import { WidgetNode } from "./widget.js";
|
|
8
7
|
class ScaleNode extends WidgetNode {
|
|
9
8
|
static priority = 1;
|
|
@@ -18,11 +17,7 @@ class ScaleNode extends WidgetNode {
|
|
|
18
17
|
scheduleAfterCommit(() => child.addMark());
|
|
19
18
|
return;
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
super.appendChild(child);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
throw new Error(`Cannot append '${child.typeName}' to 'Scale': expected x.ScaleMark or Widget`);
|
|
20
|
+
super.appendChild(child);
|
|
26
21
|
}
|
|
27
22
|
insertBefore(child, before) {
|
|
28
23
|
if (child instanceof ScaleMarkNode) {
|
|
@@ -37,11 +32,7 @@ class ScaleNode extends WidgetNode {
|
|
|
37
32
|
this.scheduleRebuildAllMarks();
|
|
38
33
|
return;
|
|
39
34
|
}
|
|
40
|
-
|
|
41
|
-
super.insertBefore(child, before);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
throw new Error(`Cannot insert '${child.typeName}' into 'Scale': expected x.ScaleMark or Widget`);
|
|
35
|
+
super.insertBefore(child, before);
|
|
45
36
|
}
|
|
46
37
|
removeChild(child) {
|
|
47
38
|
if (child instanceof ScaleMarkNode) {
|
|
@@ -52,11 +43,7 @@ class ScaleNode extends WidgetNode {
|
|
|
52
43
|
this.scheduleRebuildAllMarks(CommitPriority.HIGH);
|
|
53
44
|
return;
|
|
54
45
|
}
|
|
55
|
-
|
|
56
|
-
super.removeChild(child);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
throw new Error(`Cannot remove '${child.typeName}' from 'Scale': expected x.ScaleMark or Widget`);
|
|
46
|
+
super.removeChild(child);
|
|
60
47
|
}
|
|
61
48
|
scheduleRebuildAllMarks(priority = CommitPriority.NORMAL) {
|
|
62
49
|
scheduleAfterCommit(() => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
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 ||
|
|
13
|
+
oldProps.hscrollbarPolicy !== newProps.hscrollbarPolicy ||
|
|
14
|
+
oldProps.vscrollbarPolicy !== newProps.vscrollbarPolicy) {
|
|
15
|
+
const hPolicy = newProps.hscrollbarPolicy ?? Gtk.PolicyType.AUTOMATIC;
|
|
16
|
+
const vPolicy = newProps.vscrollbarPolicy ?? Gtk.PolicyType.AUTOMATIC;
|
|
17
|
+
this.container.setPolicy(hPolicy, vPolicy);
|
|
18
|
+
}
|
|
19
|
+
super.updateProps(filterProps(oldProps ?? {}, PROPS), filterProps(newProps, PROPS));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
registerNodeClass(ScrolledWindowNode);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Node } from "../node.js";
|
|
3
|
+
import type { Props } from "../types.js";
|
|
4
|
+
import { VirtualNode } from "./virtual.js";
|
|
5
|
+
/**
|
|
6
|
+
* Props for the ShortcutController virtual element.
|
|
7
|
+
*
|
|
8
|
+
* Attaches keyboard shortcuts to a widget. Must contain `x.Shortcut` children.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <GtkBox>
|
|
13
|
+
* <x.ShortcutController scope={Gtk.ShortcutScope.GLOBAL}>
|
|
14
|
+
* <x.Shortcut trigger="<Control>f" onActivate={toggleSearch} />
|
|
15
|
+
* <x.Shortcut trigger="<Control>q" onActivate={quit} />
|
|
16
|
+
* </x.ShortcutController>
|
|
17
|
+
* </GtkBox>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface ShortcutControllerProps extends Props {
|
|
21
|
+
/** The scope for shortcuts (LOCAL, MANAGED, or GLOBAL) */
|
|
22
|
+
scope?: Gtk.ShortcutScope;
|
|
23
|
+
}
|
|
24
|
+
export declare class ShortcutControllerNode extends VirtualNode<ShortcutControllerProps> {
|
|
25
|
+
static priority: number;
|
|
26
|
+
static matches(type: string): boolean;
|
|
27
|
+
private controller?;
|
|
28
|
+
private parentWidget?;
|
|
29
|
+
private shortcuts;
|
|
30
|
+
setParent(widget?: Gtk.Widget): void;
|
|
31
|
+
appendChild(child: Node): void;
|
|
32
|
+
removeChild(child: Node): void;
|
|
33
|
+
updateProps(oldProps: ShortcutControllerProps | null, newProps: ShortcutControllerProps): void;
|
|
34
|
+
unmount(): void;
|
|
35
|
+
private applyScope;
|
|
36
|
+
private addShortcutToController;
|
|
37
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import { registerNodeClass } from "../registry.js";
|
|
3
|
+
import { ShortcutNode } from "./shortcut.js";
|
|
4
|
+
import { VirtualNode } from "./virtual.js";
|
|
5
|
+
export class ShortcutControllerNode extends VirtualNode {
|
|
6
|
+
static priority = 1;
|
|
7
|
+
static matches(type) {
|
|
8
|
+
return type === "ShortcutController";
|
|
9
|
+
}
|
|
10
|
+
controller;
|
|
11
|
+
parentWidget;
|
|
12
|
+
shortcuts = [];
|
|
13
|
+
setParent(widget) {
|
|
14
|
+
if (this.parentWidget && this.controller) {
|
|
15
|
+
this.parentWidget.removeController(this.controller);
|
|
16
|
+
}
|
|
17
|
+
this.parentWidget = widget;
|
|
18
|
+
if (widget) {
|
|
19
|
+
this.controller = new Gtk.ShortcutController();
|
|
20
|
+
this.applyScope();
|
|
21
|
+
widget.addController(this.controller);
|
|
22
|
+
for (const shortcut of this.shortcuts) {
|
|
23
|
+
this.addShortcutToController(shortcut);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this.controller = undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
appendChild(child) {
|
|
31
|
+
if (!(child instanceof ShortcutNode)) {
|
|
32
|
+
throw new Error(`ShortcutController only accepts Shortcut children, got '${child.typeName}'`);
|
|
33
|
+
}
|
|
34
|
+
this.shortcuts.push(child);
|
|
35
|
+
if (this.controller) {
|
|
36
|
+
this.addShortcutToController(child);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
removeChild(child) {
|
|
40
|
+
if (!(child instanceof ShortcutNode))
|
|
41
|
+
return;
|
|
42
|
+
const index = this.shortcuts.indexOf(child);
|
|
43
|
+
if (index !== -1) {
|
|
44
|
+
this.shortcuts.splice(index, 1);
|
|
45
|
+
if (this.controller && child.shortcut) {
|
|
46
|
+
this.controller.removeShortcut(child.shortcut);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
updateProps(oldProps, newProps) {
|
|
51
|
+
super.updateProps(oldProps, newProps);
|
|
52
|
+
if (!oldProps || oldProps.scope !== newProps.scope) {
|
|
53
|
+
this.applyScope();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
unmount() {
|
|
57
|
+
this.setParent(undefined);
|
|
58
|
+
super.unmount();
|
|
59
|
+
}
|
|
60
|
+
applyScope() {
|
|
61
|
+
if (!this.controller)
|
|
62
|
+
return;
|
|
63
|
+
this.controller.setScope(this.props.scope ?? Gtk.ShortcutScope.LOCAL);
|
|
64
|
+
}
|
|
65
|
+
addShortcutToController(node) {
|
|
66
|
+
if (!this.controller)
|
|
67
|
+
return;
|
|
68
|
+
node.createShortcut();
|
|
69
|
+
if (node.shortcut) {
|
|
70
|
+
this.controller.addShortcut(node.shortcut);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
registerNodeClass(ShortcutControllerNode);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import type { Props } from "../types.js";
|
|
3
|
+
import { VirtualNode } from "./virtual.js";
|
|
4
|
+
/**
|
|
5
|
+
* Props for the Shortcut virtual element.
|
|
6
|
+
*
|
|
7
|
+
* Defines a keyboard shortcut. Must be a child of `x.ShortcutController`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <x.ShortcutController>
|
|
12
|
+
* <x.Shortcut trigger="<Control>s" onActivate={save} />
|
|
13
|
+
* <x.Shortcut trigger={["F5", "<Control>r"]} onActivate={refresh} />
|
|
14
|
+
* <x.Shortcut trigger="Escape" onActivate={cancel} disabled={!canCancel} />
|
|
15
|
+
* </x.ShortcutController>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export interface ShortcutProps extends Props {
|
|
19
|
+
/** The trigger string(s) using GTK accelerator format (e.g., "\<Control\>s", "F1") */
|
|
20
|
+
trigger: string | string[];
|
|
21
|
+
/**
|
|
22
|
+
* Called when the shortcut is activated.
|
|
23
|
+
* Return false to indicate the shortcut was not handled; otherwise it is considered handled.
|
|
24
|
+
*/
|
|
25
|
+
onActivate: () => boolean | void;
|
|
26
|
+
/** Whether the shortcut is disabled */
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare class ShortcutNode extends VirtualNode<ShortcutProps> {
|
|
30
|
+
static priority: number;
|
|
31
|
+
static matches(type: string): boolean;
|
|
32
|
+
shortcut?: Gtk.Shortcut;
|
|
33
|
+
private action?;
|
|
34
|
+
createShortcut(): void;
|
|
35
|
+
updateProps(oldProps: ShortcutProps | null, newProps: ShortcutProps): void;
|
|
36
|
+
unmount(): void;
|
|
37
|
+
private createTrigger;
|
|
38
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import { registerNodeClass } from "../registry.js";
|
|
3
|
+
import { VirtualNode } from "./virtual.js";
|
|
4
|
+
export class ShortcutNode extends VirtualNode {
|
|
5
|
+
static priority = 1;
|
|
6
|
+
static matches(type) {
|
|
7
|
+
return type === "Shortcut";
|
|
8
|
+
}
|
|
9
|
+
shortcut;
|
|
10
|
+
action;
|
|
11
|
+
createShortcut() {
|
|
12
|
+
const trigger = this.createTrigger();
|
|
13
|
+
this.action = new Gtk.CallbackAction(() => {
|
|
14
|
+
const result = this.props.onActivate();
|
|
15
|
+
return result !== false;
|
|
16
|
+
});
|
|
17
|
+
this.shortcut = new Gtk.Shortcut(trigger, this.action);
|
|
18
|
+
}
|
|
19
|
+
updateProps(oldProps, newProps) {
|
|
20
|
+
super.updateProps(oldProps, newProps);
|
|
21
|
+
if (this.shortcut && (oldProps?.trigger !== newProps.trigger || oldProps?.disabled !== newProps.disabled)) {
|
|
22
|
+
this.shortcut.setTrigger(this.createTrigger());
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
unmount() {
|
|
26
|
+
this.shortcut = undefined;
|
|
27
|
+
this.action = undefined;
|
|
28
|
+
super.unmount();
|
|
29
|
+
}
|
|
30
|
+
createTrigger() {
|
|
31
|
+
if (this.props.disabled) {
|
|
32
|
+
return Gtk.NeverTrigger.get();
|
|
33
|
+
}
|
|
34
|
+
const { trigger } = this.props;
|
|
35
|
+
const triggers = Array.isArray(trigger) ? trigger : [trigger];
|
|
36
|
+
if (triggers.length === 0) {
|
|
37
|
+
return Gtk.NeverTrigger.get();
|
|
38
|
+
}
|
|
39
|
+
let result = new Gtk.ShortcutTrigger(triggers[0]);
|
|
40
|
+
for (let i = 1; i < triggers.length; i++) {
|
|
41
|
+
result = new Gtk.AlternativeTrigger(result, new Gtk.ShortcutTrigger(triggers[i]));
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
registerNodeClass(ShortcutNode);
|
package/dist/nodes/slot.js
CHANGED
|
@@ -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
|
-
|
|
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() {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
+
import * as GtkSource from "@gtkx/ffi/gtksource";
|
|
3
|
+
import { VirtualNode } from "./virtual.js";
|
|
4
|
+
/**
|
|
5
|
+
* Props for the SourceBuffer virtual element.
|
|
6
|
+
*
|
|
7
|
+
* Used to declaratively configure the text buffer for a GtkSourceView with syntax highlighting,
|
|
8
|
+
* bracket matching, and other source code editing features.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <GtkSourceView>
|
|
13
|
+
* <x.SourceBuffer
|
|
14
|
+
* text={sourceCode}
|
|
15
|
+
* language="typescript"
|
|
16
|
+
* styleScheme="Adwaita-dark"
|
|
17
|
+
* highlightSyntax
|
|
18
|
+
* highlightMatchingBrackets
|
|
19
|
+
* onTextChanged={(text) => console.log("Code:", text)}
|
|
20
|
+
* />
|
|
21
|
+
* </GtkSourceView>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type SourceBufferProps = {
|
|
25
|
+
/** Text content */
|
|
26
|
+
text?: string;
|
|
27
|
+
/** Whether to enable undo/redo */
|
|
28
|
+
enableUndo?: boolean;
|
|
29
|
+
/** Callback when the text content changes */
|
|
30
|
+
onTextChanged?: (text: string) => void;
|
|
31
|
+
/** Callback when can-undo state changes */
|
|
32
|
+
onCanUndoChanged?: (canUndo: boolean) => void;
|
|
33
|
+
/** Callback when can-redo state changes */
|
|
34
|
+
onCanRedoChanged?: (canRedo: boolean) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Language for syntax highlighting.
|
|
37
|
+
* Can be a language ID string (e.g., "typescript", "python", "rust") or a GtkSource.Language object.
|
|
38
|
+
*/
|
|
39
|
+
language?: string | GtkSource.Language;
|
|
40
|
+
/**
|
|
41
|
+
* Style scheme for syntax highlighting colors.
|
|
42
|
+
* Can be a scheme ID string (e.g., "Adwaita-dark", "classic") or a GtkSource.StyleScheme object.
|
|
43
|
+
*/
|
|
44
|
+
styleScheme?: string | GtkSource.StyleScheme;
|
|
45
|
+
/** Whether to enable syntax highlighting. Defaults to true when language is set. */
|
|
46
|
+
highlightSyntax?: boolean;
|
|
47
|
+
/** Whether to highlight matching brackets when cursor is on a bracket. Defaults to true. */
|
|
48
|
+
highlightMatchingBrackets?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Whether the buffer has an implicit trailing newline.
|
|
51
|
+
* When true (default), trailing newlines are handled automatically during file load/save.
|
|
52
|
+
*/
|
|
53
|
+
implicitTrailingNewline?: boolean;
|
|
54
|
+
/** Callback when the cursor position changes */
|
|
55
|
+
onCursorMoved?: () => void;
|
|
56
|
+
/** Callback when syntax highlighting is updated for a region */
|
|
57
|
+
onHighlightUpdated?: (start: Gtk.TextIter, end: Gtk.TextIter) => void;
|
|
58
|
+
};
|
|
59
|
+
export declare class SourceBufferNode extends VirtualNode<SourceBufferProps> {
|
|
60
|
+
static priority: number;
|
|
61
|
+
private sourceView?;
|
|
62
|
+
private buffer?;
|
|
63
|
+
static matches(type: string): boolean;
|
|
64
|
+
setSourceView(sourceView: GtkSource.View): void;
|
|
65
|
+
private resolveLanguage;
|
|
66
|
+
private resolveStyleScheme;
|
|
67
|
+
private setupBuffer;
|
|
68
|
+
private applySourceProps;
|
|
69
|
+
private getBufferText;
|
|
70
|
+
private updateSignalHandlers;
|
|
71
|
+
updateProps(oldProps: SourceBufferProps | null, newProps: SourceBufferProps): void;
|
|
72
|
+
unmount(): void;
|
|
73
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { batch } from "@gtkx/ffi";
|
|
2
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
|
+
import * as GtkSource from "@gtkx/ffi/gtksource";
|
|
4
|
+
import { registerNodeClass } from "../registry.js";
|
|
5
|
+
import { signalStore } from "./internal/signal-store.js";
|
|
6
|
+
import { VirtualNode } from "./virtual.js";
|
|
7
|
+
export class SourceBufferNode extends VirtualNode {
|
|
8
|
+
static priority = 1;
|
|
9
|
+
sourceView;
|
|
10
|
+
buffer;
|
|
11
|
+
static matches(type) {
|
|
12
|
+
return type === "SourceBuffer";
|
|
13
|
+
}
|
|
14
|
+
setSourceView(sourceView) {
|
|
15
|
+
this.sourceView = sourceView;
|
|
16
|
+
this.setupBuffer();
|
|
17
|
+
}
|
|
18
|
+
resolveLanguage(language) {
|
|
19
|
+
if (typeof language === "string") {
|
|
20
|
+
const langManager = GtkSource.LanguageManager.getDefault();
|
|
21
|
+
return langManager.getLanguage(language);
|
|
22
|
+
}
|
|
23
|
+
return language;
|
|
24
|
+
}
|
|
25
|
+
resolveStyleScheme(scheme) {
|
|
26
|
+
if (typeof scheme === "string") {
|
|
27
|
+
const schemeManager = GtkSource.StyleSchemeManager.getDefault();
|
|
28
|
+
return schemeManager.getScheme(scheme);
|
|
29
|
+
}
|
|
30
|
+
return scheme;
|
|
31
|
+
}
|
|
32
|
+
setupBuffer() {
|
|
33
|
+
if (!this.sourceView)
|
|
34
|
+
return;
|
|
35
|
+
this.buffer = new GtkSource.Buffer();
|
|
36
|
+
this.sourceView.setBuffer(this.buffer);
|
|
37
|
+
if (this.props.enableUndo !== undefined) {
|
|
38
|
+
this.buffer.setEnableUndo(this.props.enableUndo);
|
|
39
|
+
}
|
|
40
|
+
if (this.props.text !== undefined) {
|
|
41
|
+
this.buffer.setText(this.props.text, -1);
|
|
42
|
+
}
|
|
43
|
+
this.applySourceProps();
|
|
44
|
+
this.updateSignalHandlers();
|
|
45
|
+
}
|
|
46
|
+
applySourceProps() {
|
|
47
|
+
if (!this.buffer)
|
|
48
|
+
return;
|
|
49
|
+
if (this.props.language !== undefined) {
|
|
50
|
+
const language = this.resolveLanguage(this.props.language);
|
|
51
|
+
this.buffer.setLanguage(language);
|
|
52
|
+
}
|
|
53
|
+
if (this.props.styleScheme !== undefined) {
|
|
54
|
+
const scheme = this.resolveStyleScheme(this.props.styleScheme);
|
|
55
|
+
this.buffer.setStyleScheme(scheme);
|
|
56
|
+
}
|
|
57
|
+
const highlightSyntax = this.props.highlightSyntax ?? this.props.language !== undefined;
|
|
58
|
+
this.buffer.setHighlightSyntax(highlightSyntax);
|
|
59
|
+
const highlightMatchingBrackets = this.props.highlightMatchingBrackets ?? true;
|
|
60
|
+
this.buffer.setHighlightMatchingBrackets(highlightMatchingBrackets);
|
|
61
|
+
if (this.props.implicitTrailingNewline !== undefined) {
|
|
62
|
+
this.buffer.setImplicitTrailingNewline(this.props.implicitTrailingNewline);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
getBufferText() {
|
|
66
|
+
const buffer = this.buffer;
|
|
67
|
+
if (!buffer)
|
|
68
|
+
return "";
|
|
69
|
+
const startIter = new Gtk.TextIter();
|
|
70
|
+
const endIter = new Gtk.TextIter();
|
|
71
|
+
batch(() => {
|
|
72
|
+
buffer.getStartIter(startIter);
|
|
73
|
+
buffer.getEndIter(endIter);
|
|
74
|
+
});
|
|
75
|
+
return buffer.getText(startIter, endIter, true);
|
|
76
|
+
}
|
|
77
|
+
updateSignalHandlers() {
|
|
78
|
+
if (!this.buffer)
|
|
79
|
+
return;
|
|
80
|
+
const buffer = this.buffer;
|
|
81
|
+
const { onTextChanged, onCanUndoChanged, onCanRedoChanged, onCursorMoved, onHighlightUpdated } = this.props;
|
|
82
|
+
signalStore.set(this, buffer, "changed", onTextChanged ? () => onTextChanged(this.getBufferText()) : null);
|
|
83
|
+
signalStore.set(this, buffer, "notify::can-undo", onCanUndoChanged ? () => onCanUndoChanged(buffer.getCanUndo()) : null);
|
|
84
|
+
signalStore.set(this, buffer, "notify::can-redo", onCanRedoChanged ? () => onCanRedoChanged(buffer.getCanRedo()) : null);
|
|
85
|
+
signalStore.set(this, buffer, "cursor-moved", onCursorMoved ?? null);
|
|
86
|
+
signalStore.set(this, buffer, "highlight-updated", onHighlightUpdated
|
|
87
|
+
? (_buffer, start, end) => onHighlightUpdated(start, end)
|
|
88
|
+
: null);
|
|
89
|
+
}
|
|
90
|
+
updateProps(oldProps, newProps) {
|
|
91
|
+
super.updateProps(oldProps, newProps);
|
|
92
|
+
if (!this.buffer)
|
|
93
|
+
return;
|
|
94
|
+
if (!oldProps || oldProps.enableUndo !== newProps.enableUndo) {
|
|
95
|
+
if (newProps.enableUndo !== undefined) {
|
|
96
|
+
this.buffer.setEnableUndo(newProps.enableUndo);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!oldProps || oldProps.text !== newProps.text) {
|
|
100
|
+
if (newProps.text !== undefined) {
|
|
101
|
+
const currentText = this.getBufferText();
|
|
102
|
+
if (currentText !== newProps.text) {
|
|
103
|
+
this.buffer.setText(newProps.text, -1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!oldProps || oldProps.language !== newProps.language) {
|
|
108
|
+
if (newProps.language !== undefined) {
|
|
109
|
+
const language = this.resolveLanguage(newProps.language);
|
|
110
|
+
this.buffer.setLanguage(language);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!oldProps || oldProps.styleScheme !== newProps.styleScheme) {
|
|
114
|
+
if (newProps.styleScheme !== undefined) {
|
|
115
|
+
const scheme = this.resolveStyleScheme(newProps.styleScheme);
|
|
116
|
+
this.buffer.setStyleScheme(scheme);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!oldProps ||
|
|
120
|
+
oldProps.highlightSyntax !== newProps.highlightSyntax ||
|
|
121
|
+
oldProps.language !== newProps.language) {
|
|
122
|
+
const highlightSyntax = newProps.highlightSyntax ?? newProps.language !== undefined;
|
|
123
|
+
this.buffer.setHighlightSyntax(highlightSyntax);
|
|
124
|
+
}
|
|
125
|
+
if (!oldProps || oldProps.highlightMatchingBrackets !== newProps.highlightMatchingBrackets) {
|
|
126
|
+
const highlightMatchingBrackets = newProps.highlightMatchingBrackets ?? true;
|
|
127
|
+
this.buffer.setHighlightMatchingBrackets(highlightMatchingBrackets);
|
|
128
|
+
}
|
|
129
|
+
if (!oldProps || oldProps.implicitTrailingNewline !== newProps.implicitTrailingNewline) {
|
|
130
|
+
if (newProps.implicitTrailingNewline !== undefined) {
|
|
131
|
+
this.buffer.setImplicitTrailingNewline(newProps.implicitTrailingNewline);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!oldProps ||
|
|
135
|
+
oldProps.onTextChanged !== newProps.onTextChanged ||
|
|
136
|
+
oldProps.onCanUndoChanged !== newProps.onCanUndoChanged ||
|
|
137
|
+
oldProps.onCanRedoChanged !== newProps.onCanRedoChanged ||
|
|
138
|
+
oldProps.onCursorMoved !== newProps.onCursorMoved ||
|
|
139
|
+
oldProps.onHighlightUpdated !== newProps.onHighlightUpdated) {
|
|
140
|
+
this.updateSignalHandlers();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
unmount() {
|
|
144
|
+
this.buffer = undefined;
|
|
145
|
+
this.sourceView = undefined;
|
|
146
|
+
super.unmount();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
registerNodeClass(SourceBufferNode);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as GtkSource from "@gtkx/ffi/gtksource";
|
|
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 {
|
|
7
|
+
static priority = 1;
|
|
8
|
+
bufferChild;
|
|
9
|
+
static matches(_type, containerOrClass) {
|
|
10
|
+
return isContainerType(GtkSource.View, containerOrClass);
|
|
11
|
+
}
|
|
12
|
+
appendChild(child) {
|
|
13
|
+
if (this.tryAttachSourceBuffer(child))
|
|
14
|
+
return;
|
|
15
|
+
super.appendChild(child);
|
|
16
|
+
}
|
|
17
|
+
insertBefore(child, before) {
|
|
18
|
+
if (this.tryAttachSourceBuffer(child))
|
|
19
|
+
return;
|
|
20
|
+
super.insertBefore(child, before);
|
|
21
|
+
}
|
|
22
|
+
removeChild(child) {
|
|
23
|
+
if (child instanceof SourceBufferNode) {
|
|
24
|
+
if (this.bufferChild === child) {
|
|
25
|
+
this.bufferChild = undefined;
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
super.removeChild(child);
|
|
30
|
+
}
|
|
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");
|
|
36
|
+
}
|
|
37
|
+
this.bufferChild = child;
|
|
38
|
+
child.setSourceView(this.container);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
registerNodeClass(SourceViewNode);
|