@effindomv2/fui-as 0.1.6 → 0.1.7

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.
@@ -128,12 +128,15 @@ export function createUiImportModule(deps: UiImportDeps) {
128
128
  ui_set_height(handle: AppHandleLike, value: number, unit: number): void {
129
129
  deps.getRuntime().ui._ui_set_height(toBigIntHandle(handle), value, unit);
130
130
  },
131
+ ui_set_fill_width(handle: AppHandleLike, fill: number): void {
132
+ deps.getRuntime().ui._ui_set_fill_width(toBigIntHandle(handle), fill);
133
+ },
134
+ ui_set_fill_height(handle: AppHandleLike, fill: number): void {
135
+ deps.getRuntime().ui._ui_set_fill_height(toBigIntHandle(handle), fill);
136
+ },
131
137
  ui_set_flex_direction(handle: AppHandleLike, direction: number): void {
132
138
  deps.getRuntime().ui._ui_set_flex_direction(toBigIntHandle(handle), direction);
133
139
  },
134
- ui_set_flex_grow(handle: AppHandleLike, grow: number): void {
135
- deps.getRuntime().ui._ui_set_flex_grow(toBigIntHandle(handle), grow);
136
- },
137
140
  ui_set_flex_basis(handle: AppHandleLike, basis: number): void {
138
141
  deps.getRuntime().ui._ui_set_flex_basis(toBigIntHandle(handle), basis);
139
142
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effindomv2/fui-as",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "license": "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial",
6
6
  "description": "EffinDom v2 AssemblyScript frontend framework SDK and browser harness",
@@ -78,7 +78,7 @@
78
78
  },
79
79
  "dependencies": {
80
80
  "@assemblyscript/loader": "^0.28.17",
81
- "@effindomv2/runtime": "0.1.1"
81
+ "@effindomv2/runtime": "0.1.2"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@as-pect/assembly": "8.1.0",
package/scripts/build.sh CHANGED
@@ -124,10 +124,10 @@ resolve_runtime_dist_dir() {
124
124
  fi
125
125
 
126
126
  candidates+=(
127
+ "${REPO_ROOT}/public/v2/browser-bridge"
128
+ "${REPO_ROOT}/v2/browser-bridge/dist"
127
129
  "${PACKAGE_DIR}/node_modules/@effindomv2/runtime/dist"
128
130
  "${REPO_ROOT}/node_modules/@effindomv2/runtime/dist"
129
- "${REPO_ROOT}/v2/browser-bridge/dist"
130
- "${REPO_ROOT}/public/v2/browser-bridge"
131
131
  )
132
132
 
133
133
  for candidate in "${candidates[@]}"; do
@@ -177,9 +177,11 @@ copy_runtime_assets() {
177
177
  cp "${RUNTIME_DIST_DIR}/icu-asset.json" "${destination}/runtime/dist/icu-asset.json"
178
178
  fi
179
179
  cp -R "${RUNTIME_DIST_DIR}/runtime" "${destination}/runtime/dist/runtime"
180
- if [ -d "${RUNTIME_DIST_DIR}/fonts" ]; then
181
- mkdir -p "${destination}/runtime"
182
- cp -R "${RUNTIME_DIST_DIR}/fonts" "${destination}/runtime/fonts"
180
+ mkdir -p "${destination}/runtime/fonts"
181
+ if [ -d "${REPO_ROOT}/public/v2/fonts" ]; then
182
+ cp -R "${REPO_ROOT}/public/v2/fonts/." "${destination}/runtime/fonts/"
183
+ elif [ -d "${RUNTIME_DIST_DIR}/fonts" ]; then
184
+ cp -R "${RUNTIME_DIST_DIR}/fonts/." "${destination}/runtime/fonts/"
183
185
  fi
184
186
  }
185
187
 
@@ -100,12 +100,16 @@ export function setHeight(handle: u64, value: f32, unit: u32): void {
100
100
  ffi.ui_set_height(handle, value, unit);
101
101
  }
102
102
 
103
- export function setFlexDirection(handle: u64, direction: u32): void {
104
- ffi.ui_set_flex_direction(handle, direction);
103
+ export function setFillWidth(handle: u64, fill: bool): void {
104
+ ffi.ui_set_fill_width(handle, fill);
105
+ }
106
+
107
+ export function setFillHeight(handle: u64, fill: bool): void {
108
+ ffi.ui_set_fill_height(handle, fill);
105
109
  }
106
110
 
107
- export function setFlexGrow(handle: u64, grow: f32): void {
108
- ffi.ui_set_flex_grow(handle, grow);
111
+ export function setFlexDirection(handle: u64, direction: u32): void {
112
+ ffi.ui_set_flex_direction(handle, direction);
109
113
  }
110
114
 
111
115
  export function setFlexBasis(handle: u64, basis: f32): void {
@@ -251,7 +251,7 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
251
251
  this.cursor(CursorStyle.Pointer);
252
252
  this.flexDirection(FlexDirection.Row);
253
253
  this.alignItems(AlignItems.Center);
254
- fieldPresenter.root.flexGrow(1.0);
254
+ fieldPresenter.root.fillWidth();
255
255
  fieldPresenter.chevronHost.child(chevronPresenter.root);
256
256
  this.child(fieldPresenter.root);
257
257
  this.child(this.popupRoot);
@@ -780,7 +780,7 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
780
780
  this.padding(0.0, 0.0, 0.0, 0.0);
781
781
  this.bgColor(0x00000000);
782
782
  this.opacity(this.isEnabled ? 1.0 : 0.6);
783
- this.fieldPresenter.root.flexGrow(1.0);
783
+ this.fieldPresenter.root.fillWidth();
784
784
  this.fieldPresenter.apply(
785
785
  theme,
786
786
  new DropdownFieldVisualState(
@@ -845,7 +845,7 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
845
845
  const previousFieldRoot = this.fieldPresenter.root;
846
846
  this.fieldPresenter = nextFieldPresenter;
847
847
  this.chevronPresenter = nextChevronPresenter;
848
- nextFieldPresenter.root.flexGrow(1.0);
848
+ nextFieldPresenter.root.fillWidth();
849
849
  nextFieldPresenter.chevronHost.addChildNode(nextChevronPresenter.root);
850
850
  const children = new Array<Node>();
851
851
  children.push(nextFieldPresenter.root);
@@ -63,8 +63,7 @@ class DefaultDropdownFieldPresenter extends DropdownFieldPresenter {
63
63
  .overflowFade(true, false)
64
64
  .verticalAlign(TextVerticalAlign.Center);
65
65
  const valueHost = new FlexBox()
66
- .width(0.0, Unit.Pixel)
67
- .flexGrow(1.0)
66
+ .fillWidth()
68
67
  .child(valueNode) as FlexBox;
69
68
  const chevronHost = new FlexBox()
70
69
  .width(DEFAULT_CHEVRON_BOX_SIZE, Unit.Pixel)
@@ -88,8 +87,7 @@ class DefaultDropdownFieldPresenter extends DropdownFieldPresenter {
88
87
  .padding(theme.spacing.md, theme.spacing.sm, theme.spacing.md, theme.spacing.sm)
89
88
  .bgColor(state.pressed && state.enabled ? theme.colors.background : theme.colors.surface);
90
89
  this.valueHost
91
- .width(0.0, Unit.Pixel)
92
- .flexGrow(1.0);
90
+ .fillWidth();
93
91
  this.valueNode
94
92
  .font(theme.fonts.body, theme.fonts.sizeBody)
95
93
  .textColor(state.enabled ? theme.colors.textPrimary : theme.colors.textMuted);
@@ -44,8 +44,7 @@ export class PressableLabeledControl extends FlexBox {
44
44
  .width(activeTheme.value.spacing.sm, Unit.Pixel)
45
45
  .height(1.0, Unit.Pixel);
46
46
  this.labelHost = new FlexBox()
47
- .flexBasis(0.0)
48
- .flexGrow(1.0);
47
+ .fillWidth();
49
48
  this.labelNode.width(100.0, Unit.Percent);
50
49
  this.labelHost.child(this.labelNode);
51
50
 
@@ -190,6 +190,7 @@ export class TextInputCore extends FlexBox {
190
190
  this.placeholderHost = new TextInputPlaceholderHost(this, this.placeholderText);
191
191
  if (profile.multiline) {
192
192
  const scrollBox = new ScrollBox(new ScrollState(), new TextInputEditorViewport(this))
193
+ .fillSize()
193
194
  .child(this.editorText) as ScrollBox;
194
195
  this.editorScrollBox = scrollBox;
195
196
  this.child(scrollBox);
@@ -488,9 +489,7 @@ export class TextInputCore extends FlexBox {
488
489
  if (scrollBox !== null) {
489
490
  scrollBox.cursor(CursorStyle.Default);
490
491
  scrollBox.viewport.cursor(editableCursor);
491
- scrollBox.width(100.0, Unit.Percent);
492
- scrollBox.height(100.0, Unit.Percent);
493
- scrollBox.flexGrow(1.0);
492
+ scrollBox.fillSize();
494
493
  this.syncScrollChromeState();
495
494
  }
496
495
  this.syncFocusChrome(theme);
@@ -8,6 +8,14 @@ export class ObjectDisposedError extends Error {
8
8
  }
9
9
  }
10
10
 
11
+ export class VirtualListItemBindingError extends Error {
12
+ constructor() {
13
+ const message = "VirtualList: item renderer not configured. Call .onBindItem() or .onBindItemWith() after construction.";
14
+ super(message);
15
+ this.name = "VirtualListItemBindingError";
16
+ }
17
+ }
18
+
11
19
  export function throwNullArgument(functionName: string, argumentName: string): void {
12
20
  error("Validation", functionName + ": " + argumentName + " must not be null");
13
21
  throw new TypeError(functionName + ": " + argumentName + " must not be null");
package/src/core/ffi.ts CHANGED
@@ -228,12 +228,15 @@ export declare function ui_set_width(handle: u64, value: f32, unit: u32): void;
228
228
  @external("effindom_v2_ui", "ui_set_height")
229
229
  export declare function ui_set_height(handle: u64, value: f32, unit: u32): void;
230
230
 
231
+ @external("effindom_v2_ui", "ui_set_fill_width")
232
+ export declare function ui_set_fill_width(handle: u64, fill: bool): void;
233
+
234
+ @external("effindom_v2_ui", "ui_set_fill_height")
235
+ export declare function ui_set_fill_height(handle: u64, fill: bool): void;
236
+
231
237
  @external("effindom_v2_ui", "ui_set_flex_direction")
232
238
  export declare function ui_set_flex_direction(handle: u64, direction: u32): void;
233
239
 
234
- @external("effindom_v2_ui", "ui_set_flex_grow")
235
- export declare function ui_set_flex_grow(handle: u64, grow: f32): void;
236
-
237
240
  @external("effindom_v2_ui", "ui_set_flex_basis")
238
241
  export declare function ui_set_flex_basis(handle: u64, basis: f32): void;
239
242
 
@@ -38,17 +38,17 @@ export class FlexBoxProps {
38
38
  widthValue: f32 = 0.0;
39
39
  widthUnit: Unit = Unit.Pixel;
40
40
  hasWidth: bool = false;
41
+ hasFillWidth: bool = false;
41
42
  heightValue: f32 = 0.0;
42
43
  heightUnit: Unit = Unit.Pixel;
43
44
  hasHeight: bool = false;
45
+ hasFillHeight: bool = false;
44
46
  flexBasisValue: f32 = 0.0;
45
47
  hasFlexBasis: bool = false;
46
48
  backgroundColor: u32 = 0;
47
49
  hasBackgroundColor: bool = false;
48
50
  flexDirectionValue: FlexDirection = FlexDirection.Column;
49
51
  hasFlexDirection: bool = false;
50
- flexGrowValue: f32 = 0.0;
51
- hasFlexGrow: bool = false;
52
52
  justifyContentValue: JustifyContent = JustifyContent.Start;
53
53
  hasJustifyContent: bool = false;
54
54
  alignItemsValue: AlignItems = AlignItems.Start;
@@ -72,9 +72,11 @@ export class FlexBox extends Node {
72
72
  private widthValue: f32 = 0.0;
73
73
  private widthUnit: Unit = Unit.Pixel;
74
74
  private hasWidth: bool = false;
75
+ private hasFillWidth: bool = false;
75
76
  private heightValue: f32 = 0.0;
76
77
  private heightUnit: Unit = Unit.Pixel;
77
78
  private hasHeight: bool = false;
79
+ private hasFillHeight: bool = false;
78
80
  private flexBasisValue: f32 = 0.0;
79
81
  private hasFlexBasis: bool = false;
80
82
  private backgroundColor: u32 = 0;
@@ -91,8 +93,6 @@ export class FlexBox extends Node {
91
93
  private borderDashOff: f32 = 0.0;
92
94
  private flexDirectionValue: FlexDirection = FlexDirection.Column;
93
95
  private hasFlexDirection: bool = false;
94
- private flexGrowValue: f32 = 0.0;
95
- private hasFlexGrow: bool = false;
96
96
  private justifyContentValue: JustifyContent = JustifyContent.Start;
97
97
  private hasJustifyContent: bool = false;
98
98
  private alignItemsValue: AlignItems = AlignItems.Start;
@@ -149,6 +149,7 @@ export class FlexBox extends Node {
149
149
  this.widthValue = value;
150
150
  this.widthUnit = unit;
151
151
  this.hasWidth = true;
152
+ this.hasFillWidth = false;
152
153
  if (this.hasBuiltHandle()) {
153
154
  ui.setWidth(this.handle, value, <u32>unit);
154
155
  this.notifyRetainedLayoutMutation();
@@ -160,6 +161,7 @@ export class FlexBox extends Node {
160
161
  this.heightValue = value;
161
162
  this.heightUnit = unit;
162
163
  this.hasHeight = true;
164
+ this.hasFillHeight = false;
163
165
  if (this.hasBuiltHandle()) {
164
166
  ui.setHeight(this.handle, value, <u32>unit);
165
167
  this.notifyRetainedLayoutMutation();
@@ -168,12 +170,20 @@ export class FlexBox extends Node {
168
170
  }
169
171
 
170
172
  fillWidth(): this {
171
- this.width(100.0, Unit.Percent);
173
+ this.hasFillWidth = true;
174
+ if (this.hasBuiltHandle()) {
175
+ ui.setFillWidth(this.handle, true);
176
+ this.notifyRetainedLayoutMutation();
177
+ }
172
178
  return this;
173
179
  }
174
180
 
175
181
  fillHeight(): this {
176
- this.height(100.0, Unit.Percent);
182
+ this.hasFillHeight = true;
183
+ if (this.hasBuiltHandle()) {
184
+ ui.setFillHeight(this.handle, true);
185
+ this.notifyRetainedLayoutMutation();
186
+ }
177
187
  return this;
178
188
  }
179
189
 
@@ -274,21 +284,6 @@ export class FlexBox extends Node {
274
284
  return this;
275
285
  }
276
286
 
277
- flexGrow(grow: f32): this {
278
- this.flexGrowValue = grow;
279
- this.hasFlexGrow = true;
280
- if (this.hasBuiltHandle()) {
281
- ui.setFlexGrow(this.handle, grow);
282
- this.notifyRetainedLayoutMutation();
283
- }
284
- return this;
285
- }
286
-
287
- grow(grow: f32 = 1.0): this {
288
- this.flexGrow(grow);
289
- return this;
290
- }
291
-
292
287
  justifyContent(justify: JustifyContent): this {
293
288
  this.justifyContentValue = justify;
294
289
  this.hasJustifyContent = true;
@@ -530,15 +525,18 @@ export class FlexBox extends Node {
530
525
  if (this.hasWidth) {
531
526
  ui.setWidth(this.handle, this.widthValue, <u32>this.widthUnit);
532
527
  }
528
+ if (this.hasFillWidth) {
529
+ ui.setFillWidth(this.handle, true);
530
+ }
533
531
  if (this.hasHeight) {
534
532
  ui.setHeight(this.handle, this.heightValue, <u32>this.heightUnit);
535
533
  }
534
+ if (this.hasFillHeight) {
535
+ ui.setFillHeight(this.handle, true);
536
+ }
536
537
  if (this.hasFlexDirection) {
537
538
  ui.setFlexDirection(this.handle, <u32>this.flexDirectionValue);
538
539
  }
539
- if (this.hasFlexGrow) {
540
- ui.setFlexGrow(this.handle, this.flexGrowValue);
541
- }
542
540
  if (this.hasFlexBasis) {
543
541
  ui.setFlexBasis(this.handle, this.flexBasisValue);
544
542
  }
@@ -569,9 +567,15 @@ export class FlexBox extends Node {
569
567
  if (props.hasWidth) {
570
568
  this.width(props.widthValue, props.widthUnit);
571
569
  }
570
+ if (props.hasFillWidth) {
571
+ this.fillWidth();
572
+ }
572
573
  if (props.hasHeight) {
573
574
  this.height(props.heightValue, props.heightUnit);
574
575
  }
576
+ if (props.hasFillHeight) {
577
+ this.fillHeight();
578
+ }
575
579
  if (props.hasFlexBasis) {
576
580
  this.flexBasis(props.flexBasisValue);
577
581
  }
@@ -581,9 +585,6 @@ export class FlexBox extends Node {
581
585
  if (props.hasFlexDirection) {
582
586
  this.flexDirection(props.flexDirectionValue);
583
587
  }
584
- if (props.hasFlexGrow) {
585
- this.flexGrow(props.flexGrowValue);
586
- }
587
588
  if (props.hasJustifyContent) {
588
589
  this.justifyContent(props.justifyContentValue);
589
590
  }
@@ -722,16 +723,16 @@ export class FlexBox extends Node {
722
723
 
723
724
  private buildFullMainAxisPercentWarning(isRow: bool): string {
724
725
  if (isRow) {
725
- return "A row container has an in-flow child using width(100.0, Unit.Percent) or fillWidth() alongside siblings. Unit.Percent is literal parent-relative sizing, not flex sharing. Use grow() when siblings should share the row.";
726
+ return "A row container has an in-flow child using width(100.0, Unit.Percent) alongside siblings. Unit.Percent is literal parent-relative sizing, not flex sharing. Use fillWidth() when the child should take remaining row space.";
726
727
  }
727
- return "A column container has an in-flow child using height(100.0, Unit.Percent) or fillHeight() alongside siblings. Unit.Percent is literal parent-relative sizing, not flex sharing. Use grow() when siblings should share the column.";
728
+ return "A column container has an in-flow child using height(100.0, Unit.Percent) alongside siblings. Unit.Percent is literal parent-relative sizing, not flex sharing. Use fillHeight() when the child should take remaining column space.";
728
729
  }
729
730
 
730
731
  private buildMainAxisPercentOverflowWarning(isRow: bool): string {
731
732
  if (isRow) {
732
- return "A row container has in-flow children whose explicit width percentages exceed 100% in total. Unit.Percent is literal parent-relative sizing, not flex sharing. Use grow() when siblings should share the row, or reduce the percentages so they fit.";
733
+ return "A row container has in-flow children whose explicit width percentages exceed 100% in total. Unit.Percent is literal parent-relative sizing, not flex sharing. Use fillWidth() for the child that should expand, or reduce the percentages so they fit.";
733
734
  }
734
- return "A column container has in-flow children whose explicit height percentages exceed 100% in total. Unit.Percent is literal parent-relative sizing, not flex sharing. Use grow() when siblings should share the column, or reduce the percentages so they fit.";
735
+ return "A column container has in-flow children whose explicit height percentages exceed 100% in total. Unit.Percent is literal parent-relative sizing, not flex sharing. Use fillHeight() for the child that should expand, or reduce the percentages so they fit.";
735
736
  }
736
737
 
737
738
  protected applyVisualStyle(): void {
@@ -49,12 +49,10 @@ export class ScrollBox extends FlexBox {
49
49
  const viewportValue = (viewportOverride === null ? new ScrollView() : viewportOverride)
50
50
  .bindScrollState(scrollState)
51
51
  .showScrollbars(false)
52
- .width(0.0, Unit.Pixel)
53
- .height(100.0, Unit.Percent)
54
- .flexGrow(1.0);
52
+ .fillSize();
55
53
  const verticalGutterValue = new FlexBox()
56
54
  .width(DEFAULT_SCROLLBAR_GUTTER, Unit.Pixel)
57
- .height(100.0, Unit.Percent)
55
+ .fillHeight()
58
56
  .onPointerDown(noopPointerCallback) as FlexBox;
59
57
  const verticalScrollBarValue = new ScrollBar(scrollState, Orientation.Vertical);
60
58
  const cornerValue = new FlexBox()
@@ -68,13 +66,13 @@ export class ScrollBox extends FlexBox {
68
66
  verticalScrollBarValue.render(),
69
67
  );
70
68
  topRowValue.onPointerDown(noopPointerCallback);
71
- topRowValue.width(100.0, Unit.Percent).height(0.0, Unit.Pixel).flexGrow(1.0);
69
+ topRowValue.fillSize();
72
70
  const bottomRowValue = Row(
73
71
  horizontalScrollBarValue.render(),
74
72
  cornerValue,
75
73
  );
76
74
  bottomRowValue.onPointerDown(noopPointerCallback);
77
- bottomRowValue.width(100.0, Unit.Percent).height(0.0, Unit.Pixel);
75
+ bottomRowValue.fillWidth();
78
76
 
79
77
  this.viewportValue = viewportValue;
80
78
  this.topRowValue = topRowValue;
@@ -38,13 +38,13 @@ export class ScrollView extends Node {
38
38
  private widthValue: f32 = 0.0;
39
39
  private widthUnit: Unit = Unit.Pixel;
40
40
  private hasWidth: bool = false;
41
+ private hasFillWidth: bool = false;
41
42
  private heightValue: f32 = 0.0;
42
43
  private heightUnit: Unit = Unit.Pixel;
43
44
  private hasHeight: bool = false;
45
+ private hasFillHeight: bool = false;
44
46
  private flexBasisValue: f32 = 0.0;
45
47
  private hasFlexBasis: bool = false;
46
- private flexGrowValue: f32 = 0.0;
47
- private hasFlexGrow: bool = false;
48
48
  private enableScrollX: bool = true;
49
49
  private enableScrollY: bool = true;
50
50
  private showScrollbarsValue: bool = true;
@@ -99,6 +99,7 @@ export class ScrollView extends Node {
99
99
  this.widthValue = value;
100
100
  this.widthUnit = unit;
101
101
  this.hasWidth = true;
102
+ this.hasFillWidth = false;
102
103
  if (unit == Unit.Pixel) {
103
104
  this._scrollState.viewportWidth.value = value;
104
105
  }
@@ -113,6 +114,7 @@ export class ScrollView extends Node {
113
114
  this.heightValue = value;
114
115
  this.heightUnit = unit;
115
116
  this.hasHeight = true;
117
+ this.hasFillHeight = false;
116
118
  if (unit == Unit.Pixel) {
117
119
  this._scrollState.viewportHeight.value = value;
118
120
  }
@@ -124,12 +126,20 @@ export class ScrollView extends Node {
124
126
  }
125
127
 
126
128
  fillWidth(): this {
127
- this.width(100.0, Unit.Percent);
129
+ this.hasFillWidth = true;
130
+ if (this.hasBuiltHandle()) {
131
+ ui.setFillWidth(this.handle, true);
132
+ this.notifyRetainedLayoutMutation();
133
+ }
128
134
  return this;
129
135
  }
130
136
 
131
137
  fillHeight(): this {
132
- this.height(100.0, Unit.Percent);
138
+ this.hasFillHeight = true;
139
+ if (this.hasBuiltHandle()) {
140
+ ui.setFillHeight(this.handle, true);
141
+ this.notifyRetainedLayoutMutation();
142
+ }
133
143
  return this;
134
144
  }
135
145
 
@@ -149,21 +159,6 @@ export class ScrollView extends Node {
149
159
  return this;
150
160
  }
151
161
 
152
- flexGrow(value: f32): this {
153
- this.flexGrowValue = value;
154
- this.hasFlexGrow = true;
155
- if (this.hasBuiltHandle()) {
156
- ui.setFlexGrow(this.handle, value);
157
- this.notifyRetainedLayoutMutation();
158
- }
159
- return this;
160
- }
161
-
162
- grow(value: f32 = 1.0): this {
163
- this.flexGrow(value);
164
- return this;
165
- }
166
-
167
162
  scrollEnabledX(flag: bool): this {
168
163
  this.enableScrollX = flag;
169
164
  if (this.hasBuiltHandle()) {
@@ -319,11 +314,14 @@ export class ScrollView extends Node {
319
314
  if (this.hasWidth) {
320
315
  ui.setWidth(this.handle, this.widthValue, <u32>this.widthUnit);
321
316
  }
317
+ if (this.hasFillWidth) {
318
+ ui.setFillWidth(this.handle, true);
319
+ }
322
320
  if (this.hasHeight) {
323
321
  ui.setHeight(this.handle, this.heightValue, <u32>this.heightUnit);
324
322
  }
325
- if (this.hasFlexGrow) {
326
- ui.setFlexGrow(this.handle, this.flexGrowValue);
323
+ if (this.hasFillHeight) {
324
+ ui.setFillHeight(this.handle, true);
327
325
  }
328
326
  if (this.hasFlexBasis) {
329
327
  ui.setFlexBasis(this.handle, this.flexBasisValue);
@@ -2,6 +2,7 @@ import { HandlerAction } from "../core/Action";
2
2
  import { Disposable, disposeAll } from "../core/Disposable";
3
3
  import { markNeedsCommit } from "../core/FrameScheduler";
4
4
  import { FlexDirection, HandleValue, Unit } from "../core/ffi";
5
+ import { VirtualListItemBindingError } from "../core/Errors";
5
6
  import { Node } from "../core/Node";
6
7
  import { FlexBox } from "./FlexBox";
7
8
  import { ScrollBar } from "./ScrollBar";
@@ -20,7 +21,7 @@ export type VirtualListBinder = (container: FlexBox, index: i32) => void;
20
21
  export class VirtualList extends FlexBox {
21
22
  private totalItemsValue: i32;
22
23
  private readonly itemHeightValue: f32;
23
- private readonly bindItemValue: VirtualListBinder;
24
+ private bindItemValue: VirtualListBinder;
24
25
  private readonly scrollStateValue: ScrollState;
25
26
  private readonly scrollBoxValue: ScrollBox;
26
27
  private readonly contentValue: FlexBox;
@@ -33,7 +34,7 @@ export class VirtualList extends FlexBox {
33
34
  private currentFirstVisibleIndex: i32 = -1;
34
35
  private currentLastVisibleIndex: i32 = -1;
35
36
 
36
- constructor(totalItems: i32, itemHeight: f32, bindItem: VirtualListBinder, maxVisible: i32 = DEFAULT_MAX_VISIBLE_ITEMS) {
37
+ constructor(totalItems: i32, itemHeight: f32, maxVisible: i32 = DEFAULT_MAX_VISIBLE_ITEMS) {
37
38
  super();
38
39
  const scrollStateValue = new ScrollState();
39
40
  const poolValue = new Array<SelectionArea>();
@@ -44,7 +45,9 @@ export class VirtualList extends FlexBox {
44
45
  const poolSizeValue = maxVisible > 0 ? maxVisible + POOL_OVERSCAN_ITEMS : POOL_OVERSCAN_ITEMS;
45
46
  this.totalItemsValue = totalItemsValue;
46
47
  this.itemHeightValue = itemHeightValue;
47
- this.bindItemValue = bindItem;
48
+ this.bindItemValue = (): void => {
49
+ throw new VirtualListItemBindingError();
50
+ };
48
51
  this.scrollStateValue = scrollStateValue;
49
52
  this.poolSizeValue = poolSizeValue;
50
53
 
@@ -95,9 +98,7 @@ export class VirtualList extends FlexBox {
95
98
  .child(this.scrollBoxValue)
96
99
  .width(FULL_SIZE, Unit.Percent)
97
100
  .height(FULL_SIZE, Unit.Percent);
98
-
99
101
  this.attachListeners();
100
- this.rebuildVisibleRange(false);
101
102
  }
102
103
 
103
104
  get scrollState(): ScrollState {
@@ -150,6 +151,9 @@ export class VirtualList extends FlexBox {
150
151
  return this.builtHandle;
151
152
  }
152
153
  const handle = super.build();
154
+ if (this.currentFirstVisibleIndex < 0 && this.totalItemsValue > 0) {
155
+ this.rebuildVisibleRange(false);
156
+ }
153
157
  ui.setSelectionAreaBarrier(handle, true);
154
158
  return handle;
155
159
  }
@@ -174,6 +178,24 @@ export class VirtualList extends FlexBox {
174
178
  return this;
175
179
  }
176
180
 
181
+ onBindItem(renderer: VirtualListBinder): this {
182
+ this.bindItemValue = renderer;
183
+ this.currentFirstVisibleIndex = -1;
184
+ this.currentLastVisibleIndex = -1;
185
+ this.rebuildVisibleRange(true);
186
+ return this;
187
+ }
188
+
189
+ onBindItemWith<Owner>(owner: Owner, renderer: (owner: Owner, container: FlexBox, index: i32) => void): this {
190
+ this.bindItemValue = (container: FlexBox, index: i32): void => {
191
+ renderer(owner, container, index);
192
+ };
193
+ this.currentFirstVisibleIndex = -1;
194
+ this.currentLastVisibleIndex = -1;
195
+ this.rebuildVisibleRange(true);
196
+ return this;
197
+ }
198
+
177
199
  updateItemCount(next: i32): void {
178
200
  this.totalItemsValue = next > 0 ? next : 0;
179
201
  this.scrollStateValue.contentHeight.value = this.totalContentHeight;
@@ -301,7 +323,7 @@ export class VirtualList extends FlexBox {
301
323
  const nextItemIndex = firstVisibleIndex + poolIndex;
302
324
  rowArea.height(this.itemHeightValue, Unit.Pixel);
303
325
  const container = changetype<FlexBox>(rowArea.getChildAt(0));
304
- this.bindItemValue(container, nextItemIndex);
326
+ this.renderItem(container, nextItemIndex);
305
327
  unchecked(this.poolItemIndexByRow[poolIndex] = nextItemIndex);
306
328
  } else {
307
329
  this.hidePoolItem(rowArea, poolIndex);
@@ -421,6 +443,10 @@ export class VirtualList extends FlexBox {
421
443
  markNeedsCommit();
422
444
  }
423
445
 
446
+ private renderItem(container: FlexBox, index: i32): void {
447
+ this.bindItemValue(container, index);
448
+ }
449
+
424
450
  private maxOffsetForCurrentViewport(): f32 {
425
451
  const viewportHeight = this.scrollStateValue.viewportHeight.value > 0.0
426
452
  ? this.scrollStateValue.viewportHeight.value