@gtkx/react 0.1.50 → 0.1.52

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.
@@ -0,0 +1,178 @@
1
+ import { isStackPageContainer, } from "../container-interfaces.js";
2
+ import { Node } from "../node.js";
3
+ export class StackNode extends Node {
4
+ static matches(type) {
5
+ return type === "Stack" || type === "Stack.Root";
6
+ }
7
+ pendingVisibleChildName = null;
8
+ addStackPage(child, props) {
9
+ const { name, title } = props;
10
+ let stackPage;
11
+ if (title !== undefined) {
12
+ stackPage = this.widget.addTitled(child, title, name ?? null);
13
+ }
14
+ else if (name !== undefined) {
15
+ stackPage = this.widget.addNamed(child, name);
16
+ }
17
+ else {
18
+ stackPage = this.widget.addChild(child);
19
+ }
20
+ this.applyStackPageProps(stackPage, props);
21
+ this.applyPendingVisibleChild();
22
+ }
23
+ applyPendingVisibleChild() {
24
+ if (this.pendingVisibleChildName !== null) {
25
+ const child = this.widget.getChildByName(this.pendingVisibleChildName);
26
+ if (child) {
27
+ this.widget.setVisibleChild(child);
28
+ this.pendingVisibleChildName = null;
29
+ }
30
+ }
31
+ }
32
+ insertStackPageBefore(child, props, _beforeChild) {
33
+ // Stack doesn't have insertBefore, so we add and rely on order
34
+ // For now, just add at the end - GTK Stack doesn't support insertion at position
35
+ this.addStackPage(child, props);
36
+ }
37
+ removeStackPage(child) {
38
+ this.widget.remove(child);
39
+ }
40
+ updateStackPageProps(child, props) {
41
+ const stackPage = this.widget.getPage(child);
42
+ this.applyStackPageProps(stackPage, props);
43
+ }
44
+ applyStackPageProps(stackPage, props) {
45
+ if (props.name !== undefined) {
46
+ stackPage.setName(props.name);
47
+ }
48
+ if (props.title !== undefined) {
49
+ stackPage.setTitle(props.title);
50
+ }
51
+ if (props.iconName !== undefined) {
52
+ stackPage.setIconName(props.iconName);
53
+ }
54
+ if (props.needsAttention !== undefined) {
55
+ stackPage.setNeedsAttention(props.needsAttention);
56
+ }
57
+ if (props.visible !== undefined) {
58
+ stackPage.setVisible(props.visible);
59
+ }
60
+ if (props.useUnderline !== undefined) {
61
+ stackPage.setUseUnderline(props.useUnderline);
62
+ }
63
+ }
64
+ attachChild(child) {
65
+ this.widget.addChild(child);
66
+ }
67
+ insertChildBefore(child, _before) {
68
+ // Stack doesn't support insertion at position
69
+ this.widget.addChild(child);
70
+ }
71
+ detachChild(child) {
72
+ this.widget.remove(child);
73
+ }
74
+ consumedProps() {
75
+ const consumed = super.consumedProps();
76
+ consumed.add("visibleChildName");
77
+ return consumed;
78
+ }
79
+ updateProps(oldProps, newProps) {
80
+ if (newProps.visibleChildName !== undefined) {
81
+ const name = newProps.visibleChildName;
82
+ const child = this.widget.getChildByName(name);
83
+ if (child) {
84
+ this.widget.setVisibleChild(child);
85
+ this.pendingVisibleChildName = null;
86
+ }
87
+ else {
88
+ // Child not yet added, defer until it's added
89
+ this.pendingVisibleChildName = name;
90
+ }
91
+ }
92
+ super.updateProps(oldProps, newProps);
93
+ }
94
+ }
95
+ export class StackPageNode extends Node {
96
+ static matches(type) {
97
+ return type === "Stack.Page";
98
+ }
99
+ isVirtual() {
100
+ return true;
101
+ }
102
+ pageProps = {};
103
+ childWidget = null;
104
+ parentContainer = null;
105
+ initialize(props) {
106
+ this.pageProps = this.extractPageProps(props);
107
+ super.initialize(props);
108
+ }
109
+ extractPageProps(props) {
110
+ return {
111
+ name: typeof props.name === "string" ? props.name : undefined,
112
+ title: typeof props.title === "string" ? props.title : undefined,
113
+ iconName: typeof props.iconName === "string" ? props.iconName : undefined,
114
+ needsAttention: typeof props.needsAttention === "boolean" ? props.needsAttention : undefined,
115
+ visible: typeof props.visible === "boolean" ? props.visible : undefined,
116
+ useUnderline: typeof props.useUnderline === "boolean" ? props.useUnderline : undefined,
117
+ };
118
+ }
119
+ getChildWidget() {
120
+ return this.childWidget;
121
+ }
122
+ appendChild(child) {
123
+ const childWidget = child.getWidget();
124
+ if (childWidget) {
125
+ this.childWidget = childWidget;
126
+ }
127
+ }
128
+ attachToParent(parent) {
129
+ if (isStackPageContainer(parent) && this.childWidget) {
130
+ this.parentContainer = parent;
131
+ parent.addStackPage(this.childWidget, this.pageProps);
132
+ }
133
+ }
134
+ attachToParentBefore(parent, before) {
135
+ if (isStackPageContainer(parent) && this.childWidget) {
136
+ this.parentContainer = parent;
137
+ const beforePage = before instanceof StackPageNode ? before.getChildWidget() : before.getWidget();
138
+ if (beforePage) {
139
+ parent.insertStackPageBefore(this.childWidget, this.pageProps, beforePage);
140
+ }
141
+ else {
142
+ parent.addStackPage(this.childWidget, this.pageProps);
143
+ }
144
+ }
145
+ }
146
+ detachFromParent(parent) {
147
+ if (isStackPageContainer(parent) && this.childWidget) {
148
+ parent.removeStackPage(this.childWidget);
149
+ this.parentContainer = null;
150
+ }
151
+ }
152
+ consumedProps() {
153
+ const consumed = super.consumedProps();
154
+ consumed.add("name");
155
+ consumed.add("title");
156
+ consumed.add("iconName");
157
+ consumed.add("needsAttention");
158
+ consumed.add("visible");
159
+ consumed.add("useUnderline");
160
+ return consumed;
161
+ }
162
+ updateProps(oldProps, newProps) {
163
+ const newPageProps = this.extractPageProps(newProps);
164
+ const propsChanged = oldProps.name !== newProps.name ||
165
+ oldProps.title !== newProps.title ||
166
+ oldProps.iconName !== newProps.iconName ||
167
+ oldProps.needsAttention !== newProps.needsAttention ||
168
+ oldProps.visible !== newProps.visible ||
169
+ oldProps.useUnderline !== newProps.useUnderline;
170
+ if (propsChanged) {
171
+ this.pageProps = newPageProps;
172
+ if (this.parentContainer && this.childWidget) {
173
+ this.parentContainer.updateStackPageProps(this.childWidget, this.pageProps);
174
+ }
175
+ }
176
+ super.updateProps(oldProps, newProps);
177
+ }
178
+ }
@@ -3,7 +3,6 @@ import type { Props } from "../factory.js";
3
3
  import { Node } from "../node.js";
4
4
  export declare class TextViewNode extends Node<Gtk.TextView> {
5
5
  static matches(type: string): boolean;
6
- constructor(type: string, props: Props);
7
6
  protected consumedProps(): Set<string>;
8
7
  updateProps(oldProps: Props, newProps: Props): void;
9
8
  }
@@ -3,13 +3,6 @@ export class TextViewNode extends Node {
3
3
  static matches(type) {
4
4
  return type === "TextView";
5
5
  }
6
- constructor(type, props) {
7
- super(type, props);
8
- const buffer = props.buffer;
9
- if (buffer) {
10
- this.widget.setBuffer(buffer);
11
- }
12
- }
13
6
  consumedProps() {
14
7
  const consumed = super.consumedProps();
15
8
  consumed.add("buffer");
package/dist/types.d.ts CHANGED
@@ -7,7 +7,12 @@ import type { ReactElement, ReactNode } from "react";
7
7
  export interface SlotProps {
8
8
  children?: ReactNode;
9
9
  }
10
+ /**
11
+ * Props passed to list item components.
12
+ * @typeParam I - The type of the data item
13
+ */
10
14
  export interface ListItemProps<I = unknown> {
15
+ /** The data item to render. */
11
16
  item: I;
12
17
  }
13
18
  export interface GridChildProps extends SlotProps {
@@ -21,7 +26,12 @@ export interface GridChildProps extends SlotProps {
21
26
  * Called with null during setup (for loading state) and with the actual item during bind.
22
27
  */
23
28
  export type RenderItemFn<T> = (item: T | null) => ReactElement;
29
+ /**
30
+ * Props for ListView and GridView components.
31
+ * @typeParam T - The type of the data items in the list
32
+ */
24
33
  export interface ListViewRenderProps<T = unknown> {
34
+ /** Render function called for each item in the list. */
25
35
  renderItem: RenderItemFn<T>;
26
36
  }
27
37
  /**
@@ -32,11 +42,20 @@ export interface ListViewRenderProps<T = unknown> {
32
42
  * @param columnId - The ID of the column being sorted
33
43
  */
34
44
  export type ColumnSortFn<T, C extends string = string> = (a: T, b: T, columnId: C) => number;
45
+ /**
46
+ * Props for individual columns in a ColumnView.
47
+ * @typeParam T - The type of the data items displayed in the column
48
+ */
35
49
  export interface ColumnViewColumnProps<T = unknown> {
50
+ /** The column header title. */
36
51
  title?: string;
52
+ /** Whether the column should expand to fill available space. */
37
53
  expand?: boolean;
54
+ /** Whether the column can be resized by the user. */
38
55
  resizable?: boolean;
56
+ /** Fixed width in pixels. Overrides automatic sizing. */
39
57
  fixedWidth?: number;
58
+ /** Unique identifier for the column. Used for sorting. */
40
59
  id?: string;
41
60
  /**
42
61
  * Render function for column cells.
@@ -45,12 +64,69 @@ export interface ColumnViewColumnProps<T = unknown> {
45
64
  */
46
65
  renderCell: (item: T | null) => ReactElement;
47
66
  }
67
+ /**
68
+ * Props for the ColumnView root component.
69
+ * @typeParam T - The type of the data items in the view
70
+ * @typeParam C - The union type of column IDs
71
+ */
48
72
  export interface ColumnViewRootProps<T = unknown, C extends string = string> {
73
+ /** The ID of the currently sorted column, or null if unsorted. */
49
74
  sortColumn?: C | null;
75
+ /** The current sort direction. */
50
76
  sortOrder?: SortType;
77
+ /** Callback fired when the user changes the sort column or order. */
51
78
  onSortChange?: (column: C | null, order: SortType) => void;
79
+ /** Custom comparison function for sorting items. */
52
80
  sortFn?: ColumnSortFn<T, C>;
53
81
  }
54
82
  export interface NotebookPageProps extends SlotProps {
55
83
  label: string;
56
84
  }
85
+ export interface StackRootProps extends SlotProps {
86
+ visibleChildName?: string;
87
+ }
88
+ export interface StackPageProps extends SlotProps {
89
+ name?: string;
90
+ title?: string;
91
+ iconName?: string;
92
+ needsAttention?: boolean;
93
+ visible?: boolean;
94
+ useUnderline?: boolean;
95
+ }
96
+ /**
97
+ * Props for the Menu.Root component.
98
+ * Root container for declarative menu structures.
99
+ */
100
+ export interface MenuRootProps {
101
+ children?: ReactNode;
102
+ }
103
+ /**
104
+ * Props for Menu.Item components.
105
+ * Represents a single menu item with an action.
106
+ */
107
+ export interface MenuItemProps {
108
+ /** The visible label for the menu item. */
109
+ label: string;
110
+ /** Callback invoked when the menu item is activated. */
111
+ onActivate?: () => void;
112
+ /** Keyboard accelerators for this menu item (e.g., `"<Control>q"` or `["<Control>q", "<Control>w"]`). */
113
+ accels?: string | string[];
114
+ }
115
+ /**
116
+ * Props for Menu.Section components.
117
+ * Groups related menu items with optional label.
118
+ */
119
+ export interface MenuSectionProps {
120
+ /** Optional section label displayed as a header. */
121
+ label?: string;
122
+ children?: ReactNode;
123
+ }
124
+ /**
125
+ * Props for Menu.Submenu components.
126
+ * Creates a nested submenu with its own items.
127
+ */
128
+ export interface MenuSubmenuProps {
129
+ /** The submenu label shown in parent menu. */
130
+ label: string;
131
+ children?: ReactNode;
132
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/react",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "description": "Build GTK4 desktop applications with React and TypeScript",
5
5
  "keywords": [
6
6
  "gtk",
@@ -36,10 +36,10 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "react-reconciler": "0.33.0",
39
- "@gtkx/ffi": "0.1.50"
39
+ "@gtkx/ffi": "0.1.52"
40
40
  },
41
41
  "devDependencies": {
42
- "@gtkx/gir": "0.1.50"
42
+ "@gtkx/gir": "0.1.52"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": "^19"