Skip to content

Commit 3187f8a

Browse files
authored
Added support for QGridLayout (#221)
* Initial rendering support of GridView * Keep track of positions of rows and columns * Added proper errors for foreign children * Support controlling height and width of units * Implemented column/row stretching and min sizing * Fixed stale props being sent to GridRow and fixed removing rows/columns
1 parent 5274623 commit 3187f8a

File tree

10 files changed

+858
-125
lines changed

10 files changed

+858
-125
lines changed

package-lock.json

Lines changed: 93 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"react": "^16.9.0"
3333
},
3434
"devDependencies": {
35-
"@nodegui/nodegui": "^0.18.0",
35+
"@nodegui/nodegui": "^0.21.0",
3636
"@types/node": "^13.9.3",
3737
"prettier": "^1.18.2",
3838
"react": "^16.13.1",
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { FunctionComponentElement } from "react";
2+
import { Component, NodeWidget } from "@nodegui/nodegui";
3+
import { RNComponent } from "../../config";
4+
import { RNGridRow } from "../GridRow/RNGridRow";
5+
6+
export type GridColumnProps = {
7+
/**
8+
* The number of horizontal units to occupy
9+
*/
10+
width?: number;
11+
};
12+
13+
const setGridColumnProps = (
14+
widget: RNGridColumn,
15+
parentRow: RNGridRow,
16+
newProps: GridColumnProps,
17+
oldProps: GridColumnProps
18+
) => {
19+
if (widget.actualWidget) {
20+
// TODO: Optimize this
21+
parentRow.parentGrid?.layout?.removeWidget(widget.actualWidget);
22+
parentRow.parentGrid?.layout?.addWidget(
23+
widget.actualWidget,
24+
parentRow.rowIndex ?? 0,
25+
widget.columnIndex ?? 0,
26+
parentRow.height ?? 1,
27+
widget.width ?? 1
28+
);
29+
}
30+
31+
const setter: GridColumnProps = {
32+
set width(width: number) {
33+
widget.width = width;
34+
},
35+
};
36+
Object.assign(setter, newProps);
37+
};
38+
39+
export class RNGridColumn extends Component implements RNComponent {
40+
native: any;
41+
actualWidget?: NodeWidget<any>;
42+
parentRow?: RNGridRow;
43+
latestProps?: GridColumnProps;
44+
prevProps?: GridColumnProps;
45+
columnIndex?: number;
46+
width?: number;
47+
48+
setParentRowAndUpdateProps(parentRow: RNGridRow, index: number): void {
49+
this.parentRow = parentRow;
50+
this.columnIndex = index;
51+
setGridColumnProps(
52+
this,
53+
parentRow,
54+
this.latestProps ?? {},
55+
this.prevProps ?? {}
56+
);
57+
}
58+
59+
remove(): void {
60+
if (!this.actualWidget) {
61+
return;
62+
}
63+
64+
this.parentRow?.parentGrid?.layout?.removeWidget(this.actualWidget);
65+
this.actualWidget.close();
66+
this.actualWidget = undefined;
67+
}
68+
69+
/* RNComponent */
70+
71+
setProps(newProps: GridColumnProps, oldProps: GridColumnProps): void {
72+
if (this.parentRow) {
73+
setGridColumnProps(this, this.parentRow, newProps, oldProps);
74+
}
75+
76+
this.latestProps = newProps;
77+
this.prevProps = oldProps;
78+
}
79+
appendInitialChild(child: NodeWidget<any>): void {
80+
if (this.actualWidget) {
81+
throw new Error("Grid column can have only one child");
82+
}
83+
this.actualWidget = child;
84+
}
85+
appendChild(child: NodeWidget<any>): void {
86+
this.appendInitialChild(child);
87+
}
88+
insertBefore(child: NodeWidget<any>, beforeChild: NodeWidget<any>): void {
89+
this.appendInitialChild(child);
90+
}
91+
removeChild(child: NodeWidget<any>): void {
92+
this.remove();
93+
}
94+
static tagName: string = "gridcolumn";
95+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Fiber } from "react-reconciler";
2+
import { GridColumnProps, RNGridColumn } from "./RNGridColumn";
3+
import { AppContainer } from "../../../reconciler";
4+
import { registerComponent, ComponentConfig } from "../../config";
5+
6+
class GridColumnConfig extends ComponentConfig {
7+
tagName = RNGridColumn.tagName;
8+
shouldSetTextContent(nextProps: GridColumnProps): boolean {
9+
return false;
10+
}
11+
createInstance(
12+
newProps: GridColumnProps,
13+
rootInstance: AppContainer,
14+
context: any,
15+
workInProgress: Fiber
16+
): RNGridColumn {
17+
const widget = new RNGridColumn();
18+
widget.setProps(newProps, newProps);
19+
return widget;
20+
}
21+
finalizeInitialChildren(
22+
instance: RNGridColumn,
23+
newProps: GridColumnProps,
24+
rootContainerInstance: AppContainer,
25+
context: any
26+
): boolean {
27+
return true;
28+
}
29+
commitMount(
30+
instance: RNGridColumn,
31+
newProps: GridColumnProps,
32+
internalInstanceHandle: any
33+
): void {
34+
return;
35+
}
36+
commitUpdate(
37+
instance: RNGridColumn,
38+
updatePayload: any,
39+
oldProps: GridColumnProps,
40+
newProps: GridColumnProps,
41+
finishedWork: Fiber
42+
): void {
43+
instance.setProps(newProps, oldProps);
44+
}
45+
}
46+
47+
export const GridColumn = registerComponent<GridColumnProps>(
48+
new GridColumnConfig()
49+
);
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { FunctionComponentElement } from "react";
2+
import { GridColumnProps, RNGridColumn } from "../GridColumn/RNGridColumn";
3+
import { Component } from "@nodegui/nodegui";
4+
import { RNComponent } from "../../config";
5+
import { RNGridView } from "../RNGridView";
6+
import {
7+
DataWithOffset,
8+
updateDisplacedChildren,
9+
offsetForIndex,
10+
} from "../utils";
11+
12+
export type GridRowProps = {
13+
children:
14+
| Array<FunctionComponentElement<GridColumnProps>>
15+
| FunctionComponentElement<GridColumnProps>;
16+
17+
/**
18+
* The number of vertical units to occupy
19+
*/
20+
height?: number;
21+
};
22+
23+
const setGridRowProps = (
24+
widget: RNGridRow,
25+
parentGrid: RNGridView,
26+
newProps: Omit<GridRowProps, "children">,
27+
oldProps: Omit<GridRowProps, "children">
28+
) => {
29+
const setter: Omit<GridRowProps, "children"> = {
30+
set height(height: number) {
31+
widget.height = height;
32+
},
33+
};
34+
Object.assign(setter, newProps);
35+
};
36+
37+
export class RNGridRow extends Component implements RNComponent {
38+
native: any;
39+
parentGrid?: RNGridView;
40+
latestProps?: GridRowProps;
41+
prevProps?: GridRowProps;
42+
childColumns: Array<DataWithOffset<RNGridColumn>> = [];
43+
rowIndex?: number;
44+
height?: number;
45+
46+
setParentGridAndUpdateProps(parentGrid: RNGridView, index: number): void {
47+
this.parentGrid = parentGrid;
48+
this.rowIndex = index;
49+
setGridRowProps(
50+
this,
51+
parentGrid,
52+
this.latestProps ?? {},
53+
this.prevProps ?? {}
54+
);
55+
56+
this.updateChildren();
57+
}
58+
59+
updateChildren(startIndex = 0): void {
60+
updateDisplacedChildren<RNGridColumn, RNGridRow>(
61+
startIndex,
62+
this.childColumns,
63+
this,
64+
"width",
65+
"setParentRowAndUpdateProps"
66+
);
67+
}
68+
69+
remove(): void {
70+
this.childColumns.forEach(({ data }) => data.remove());
71+
}
72+
73+
/* RNComponent */
74+
75+
setProps(newProps: GridRowProps, oldProps: GridRowProps): void {
76+
if (this.parentGrid) {
77+
setGridRowProps(this, this.parentGrid, newProps, oldProps);
78+
}
79+
80+
this.latestProps = newProps;
81+
this.prevProps = oldProps;
82+
}
83+
appendInitialChild(child: RNGridColumn): void {
84+
this.appendChild(child);
85+
}
86+
appendChild(child: RNGridColumn): void {
87+
if (!(child instanceof RNGridColumn)) {
88+
throw new Error("GridColumn is the only supported child of GridRow");
89+
}
90+
91+
const offset = offsetForIndex<RNGridColumn>(
92+
this.childColumns.length,
93+
this.childColumns,
94+
"width"
95+
);
96+
97+
child.setParentRowAndUpdateProps(this, offset);
98+
99+
this.childColumns.push({
100+
offset,
101+
data: child,
102+
});
103+
}
104+
insertBefore(child: RNGridColumn, beforeChild: RNGridColumn): void {
105+
const prevIndex = this.childColumns.findIndex(
106+
({ data }) => data === beforeChild
107+
);
108+
109+
if (prevIndex === -1) {
110+
throw new Error(
111+
"Attempted to insert child GridColumn before nonexistent column"
112+
);
113+
}
114+
115+
const offset = offsetForIndex<RNGridColumn>(
116+
prevIndex,
117+
this.childColumns,
118+
"width"
119+
);
120+
121+
this.childColumns.splice(prevIndex, 0, {
122+
offset,
123+
data: child,
124+
});
125+
// Update displaced children
126+
this.updateChildren(prevIndex);
127+
}
128+
removeChild(child: RNGridColumn): void {
129+
const prevIndex = this.childColumns.findIndex(({ data }) => data === child);
130+
131+
if (prevIndex !== -1) {
132+
this.childColumns.splice(prevIndex, 1);
133+
this.updateChildren(prevIndex);
134+
}
135+
136+
// Actually remove child from layout
137+
child.remove();
138+
child.parentRow = undefined;
139+
}
140+
static tagName: string = "gridrow";
141+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Fiber } from "react-reconciler";
2+
import { AppContainer } from "../../../reconciler";
3+
import { registerComponent, ComponentConfig } from "../../config";
4+
import { RNGridRow, GridRowProps } from "./RNGridRow";
5+
6+
class GridRowConfig extends ComponentConfig {
7+
tagName = RNGridRow.tagName;
8+
shouldSetTextContent(nextProps: GridRowProps): boolean {
9+
return false;
10+
}
11+
createInstance(
12+
newProps: GridRowProps,
13+
rootInstance: AppContainer,
14+
context: any,
15+
workInProgress: Fiber
16+
): RNGridRow {
17+
const widget = new RNGridRow();
18+
widget.setProps(newProps, newProps);
19+
return widget;
20+
}
21+
finalizeInitialChildren(
22+
instance: RNGridRow,
23+
newProps: GridRowProps,
24+
rootContainerInstance: AppContainer,
25+
context: any
26+
): boolean {
27+
return true;
28+
}
29+
commitMount(
30+
instance: RNGridRow,
31+
newProps: GridRowProps,
32+
internalInstanceHandle: any
33+
): void {
34+
return;
35+
}
36+
commitUpdate(
37+
instance: RNGridRow,
38+
updatePayload: any,
39+
oldProps: GridRowProps,
40+
newProps: GridRowProps,
41+
finishedWork: Fiber
42+
): void {
43+
instance.setProps(newProps, oldProps);
44+
}
45+
}
46+
47+
export const GridRow = registerComponent<GridRowProps>(new GridRowConfig());

0 commit comments

Comments
 (0)