uicore-ts 1.1.102 → 1.1.105

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.
@@ -32,39 +32,12 @@ export declare class UITableView extends UINativeScrollView {
32
32
  _shouldAnimateNextLayout?: boolean;
33
33
  usesVirtualLayoutingForIntrinsicSizing: boolean;
34
34
  animationDuration: number;
35
- private _useViewportScrolling;
36
- private _windowScrollHandler?;
37
- private _resizeHandler?;
38
- private _intersectionObserver?;
35
+ _intersectionObserver?: IntersectionObserver;
39
36
  constructor(elementID?: string);
40
- /**
41
- * Automatically detect if this table should use viewport scrolling
42
- * If the table's bounds height is >= the total content height,
43
- * then it doesn't need internal scrolling and should use viewport scrolling
44
- */
45
- private _autoDetectScrollMode;
46
- /**
47
- * Enable viewport-based virtual scrolling for full-height tables
48
- * This allows the table to be part of the page flow while still
49
- * benefiting from virtual scrolling performance
50
- */
51
- enableViewportBasedVirtualScrolling(): void;
52
- /**
53
- * Disable viewport scrolling and return to normal scroll behavior
54
- */
55
- disableViewportBasedVirtualScrolling(): void;
56
- private _setupViewportScrollListeners;
57
- private _cleanupViewportScrollListeners;
58
- private _scheduleDrawVisibleRowsInViewport;
59
- /**
60
- * Calculate which rows are visible in the browser viewport
61
- * rather than in the scrollview's content area
62
- */
63
- indexesForVisibleRowsInViewport(paddingRatio?: number): number[];
64
- /**
65
- * Draw visible rows based on viewport position
66
- */
67
- private _drawVisibleRowsInViewport;
37
+ _windowScrollHandler: () => void;
38
+ _resizeHandler: () => void;
39
+ _setupViewportScrollAndResizeHandlersIfNeeded(): void;
40
+ _cleanupViewportScrollListeners(): void;
68
41
  loadData(): void;
69
42
  reloadData(): void;
70
43
  highlightChanges(previousData: any[], newData: any[]): void;
@@ -76,6 +49,7 @@ export declare class UITableView extends UINativeScrollView {
76
49
  _removeVisibleRows(): void;
77
50
  _removeAllReusableRows(): void;
78
51
  _markReusableViewAsUnused(row: UIView): void;
52
+ _scheduleDrawVisibleRows(): void;
79
53
  _drawVisibleRows(): void;
80
54
  visibleRowWithIndex(rowIndex: number | undefined): UIView;
81
55
  isRowWithIndexVisible(rowIndex: number): boolean;
@@ -87,6 +61,7 @@ export declare class UITableView extends UINativeScrollView {
87
61
  persistenceDataItemForRowWithIndex(rowIndex: number, row: UIView): any;
88
62
  viewForRowWithIndex(rowIndex: number): UITableViewRowView;
89
63
  didScrollToPosition(offsetPosition: UIPoint): void;
64
+ willMoveToSuperview(superview: UIView): void;
90
65
  wasAddedToViewTree(): void;
91
66
  wasRemovedFromViewTree(): void;
92
67
  setFrame(rectangle: UIRectangle, zIndex?: number, performUncheckedLayout?: boolean): void;
@@ -43,61 +43,38 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
43
43
  this._isDrawVisibleRowsScheduled = import_UIObject.NO;
44
44
  this.usesVirtualLayoutingForIntrinsicSizing = import_UIObject.NO;
45
45
  this.animationDuration = 0.25;
46
- this._useViewportScrolling = import_UIObject.NO;
47
- this._fullHeightView = new import_UIView.UIView();
48
- this._fullHeightView.hidden = import_UIObject.YES;
49
- this._fullHeightView.userInteractionEnabled = import_UIObject.NO;
50
- this.addSubview(this._fullHeightView);
51
- this.scrollsX = import_UIObject.NO;
52
- this._autoDetectScrollMode();
53
- }
54
- _autoDetectScrollMode() {
55
- const checkScrollMode = () => {
46
+ this._windowScrollHandler = () => {
56
47
  if (!this.isMemberOfViewTree) {
57
48
  return;
58
49
  }
59
- this._calculateAllPositions();
60
- const totalContentHeight = this._rowPositions.length > 0 ? this._rowPositions[this._rowPositions.length - 1].bottomY : 0;
61
- const tableBoundsHeight = this.bounds.height;
62
- if (tableBoundsHeight >= totalContentHeight) {
63
- this.enableViewportBasedVirtualScrolling();
50
+ this._scheduleDrawVisibleRows();
51
+ };
52
+ this._resizeHandler = () => {
53
+ if (!this.isMemberOfViewTree) {
54
+ return;
64
55
  }
56
+ this._rowPositions.everyElement.isValid = import_UIObject.NO;
57
+ this._highestValidRowPositionIndex = -1;
58
+ this._scheduleDrawVisibleRows();
65
59
  };
66
- import_UIView.UIView.runFunctionBeforeNextFrame(checkScrollMode);
67
- }
68
- enableViewportBasedVirtualScrolling() {
69
- if (this._useViewportScrolling) {
70
- return;
71
- }
72
- this._useViewportScrolling = import_UIObject.YES;
60
+ this._fullHeightView = new import_UIView.UIView();
61
+ this._fullHeightView.hidden = import_UIObject.YES;
62
+ this._fullHeightView.userInteractionEnabled = import_UIObject.NO;
63
+ this.addSubview(this._fullHeightView);
73
64
  this.scrollsX = import_UIObject.NO;
74
- this.scrollsY = import_UIObject.NO;
75
- this._setupViewportScrollListeners();
65
+ this._setupViewportScrollAndResizeHandlersIfNeeded();
76
66
  }
77
- disableViewportBasedVirtualScrolling() {
78
- if (!this._useViewportScrolling) {
67
+ _setupViewportScrollAndResizeHandlersIfNeeded() {
68
+ if (this._intersectionObserver) {
79
69
  return;
80
70
  }
81
- this._useViewportScrolling = import_UIObject.NO;
82
- this.scrollsY = import_UIObject.YES;
83
- this._cleanupViewportScrollListeners();
84
- }
85
- _setupViewportScrollListeners() {
86
- this._windowScrollHandler = () => {
87
- this._scheduleDrawVisibleRowsInViewport();
88
- };
89
- this._resizeHandler = () => {
90
- this._rowPositions.forEach((pos) => pos.isValid = import_UIObject.NO);
91
- this._highestValidRowPositionIndex = -1;
92
- this._scheduleDrawVisibleRowsInViewport();
93
- };
94
71
  window.addEventListener("scroll", this._windowScrollHandler, { passive: true });
95
72
  window.addEventListener("resize", this._resizeHandler, { passive: true });
96
73
  this._intersectionObserver = new IntersectionObserver(
97
74
  (entries) => {
98
75
  entries.forEach((entry) => {
99
- if (entry.isIntersecting) {
100
- this._scheduleDrawVisibleRowsInViewport();
76
+ if (entry.isIntersecting && this.isMemberOfViewTree) {
77
+ this._scheduleDrawVisibleRows();
101
78
  }
102
79
  });
103
80
  },
@@ -110,108 +87,13 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
110
87
  this._intersectionObserver.observe(this.viewHTMLElement);
111
88
  }
112
89
  _cleanupViewportScrollListeners() {
113
- if (this._windowScrollHandler) {
114
- window.removeEventListener("scroll", this._windowScrollHandler);
115
- this._windowScrollHandler = void 0;
116
- }
117
- if (this._resizeHandler) {
118
- window.removeEventListener("resize", this._resizeHandler);
119
- this._resizeHandler = void 0;
120
- }
90
+ window.removeEventListener("scroll", this._windowScrollHandler);
91
+ window.removeEventListener("resize", this._resizeHandler);
121
92
  if (this._intersectionObserver) {
122
93
  this._intersectionObserver.disconnect();
123
94
  this._intersectionObserver = void 0;
124
95
  }
125
96
  }
126
- _scheduleDrawVisibleRowsInViewport() {
127
- if (!this._isDrawVisibleRowsScheduled) {
128
- this._isDrawVisibleRowsScheduled = import_UIObject.YES;
129
- import_UIView.UIView.runFunctionBeforeNextFrame(() => {
130
- this._calculateAllPositions();
131
- this._drawVisibleRowsInViewport();
132
- this.setNeedsLayout();
133
- this._isDrawVisibleRowsScheduled = import_UIObject.NO;
134
- });
135
- }
136
- }
137
- indexesForVisibleRowsInViewport(paddingRatio = 0.5) {
138
- const tableRect = this.viewHTMLElement.getBoundingClientRect();
139
- const viewportHeight = window.innerHeight;
140
- const pageScale = import_UIView.UIView.pageScale;
141
- const visibleTop = Math.max(0, -tableRect.top / pageScale);
142
- const visibleBottom = Math.min(tableRect.height / pageScale, (viewportHeight - tableRect.top) / pageScale);
143
- const paddingPx = viewportHeight / pageScale * paddingRatio;
144
- const firstVisibleY = Math.max(0, visibleTop - paddingPx);
145
- const lastVisibleY = Math.min(tableRect.height / pageScale, visibleBottom + paddingPx);
146
- const numberOfRows = this.numberOfRows();
147
- if (this.allRowsHaveEqualHeight) {
148
- const rowHeight = this.heightForRowWithIndex(0);
149
- let firstIndex = Math.floor(firstVisibleY / rowHeight);
150
- let lastIndex = Math.floor(lastVisibleY / rowHeight);
151
- firstIndex = Math.max(firstIndex, 0);
152
- lastIndex = Math.min(lastIndex, numberOfRows - 1);
153
- const result2 = [];
154
- for (let i = firstIndex; i <= lastIndex; i++) {
155
- result2.push(i);
156
- }
157
- return result2;
158
- }
159
- this._calculateAllPositions();
160
- const rowPositions = this._rowPositions;
161
- const result = [];
162
- for (let i = 0; i < numberOfRows; i++) {
163
- const position = rowPositions[i];
164
- if (!position)
165
- break;
166
- const rowTop = position.topY;
167
- const rowBottom = position.bottomY;
168
- if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {
169
- result.push(i);
170
- }
171
- if (rowTop > lastVisibleY) {
172
- break;
173
- }
174
- }
175
- return result;
176
- }
177
- _drawVisibleRowsInViewport() {
178
- if (!this.isMemberOfViewTree) {
179
- return;
180
- }
181
- const visibleIndexes = this.indexesForVisibleRowsInViewport();
182
- const minIndex = visibleIndexes[0];
183
- const maxIndex = visibleIndexes[visibleIndexes.length - 1];
184
- const removedViews = [];
185
- const visibleRows = [];
186
- this._visibleRows.forEach((row) => {
187
- if ((0, import_UIObject.IS_DEFINED)(row._UITableViewRowIndex) && (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {
188
- this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(
189
- row._UITableViewRowIndex,
190
- row
191
- );
192
- this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row);
193
- removedViews.push(row);
194
- } else {
195
- visibleRows.push(row);
196
- }
197
- });
198
- this._visibleRows = visibleRows;
199
- visibleIndexes.forEach((rowIndex) => {
200
- if (this.isRowWithIndexVisible(rowIndex)) {
201
- return;
202
- }
203
- const view = this.viewForRowWithIndex(rowIndex);
204
- this._firstLayoutVisibleRows.push(view);
205
- this._visibleRows.push(view);
206
- this.addSubview(view);
207
- });
208
- for (let i = 0; i < removedViews.length; i++) {
209
- const view = removedViews[i];
210
- if (this._visibleRows.indexOf(view) == -1) {
211
- view.removeFromSuperview();
212
- }
213
- }
214
- }
215
97
  loadData() {
216
98
  this._persistedData = [];
217
99
  this._calculatePositionsUntilIndex(this.numberOfRows() - 1);
@@ -289,37 +171,49 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
289
171
  }
290
172
  }
291
173
  indexesForVisibleRows(paddingRatio = 0.5) {
292
- if (this._useViewportScrolling) {
293
- return this.indexesForVisibleRowsInViewport(paddingRatio);
174
+ const tableRect = this.viewHTMLElement.getBoundingClientRect();
175
+ const viewportHeight = window.innerHeight;
176
+ const pageScale = import_UIView.UIView.pageScale;
177
+ const visibleFrameTop = Math.max(0, -tableRect.top / pageScale);
178
+ const visibleFrameBottom = Math.min(
179
+ this.bounds.height,
180
+ (viewportHeight - tableRect.top) / pageScale
181
+ );
182
+ if (visibleFrameBottom <= visibleFrameTop) {
183
+ return [];
294
184
  }
295
- const firstVisibleY = this.contentOffset.y - this.bounds.height * paddingRatio;
296
- const lastVisibleY = firstVisibleY + this.bounds.height * (1 + paddingRatio);
185
+ let firstVisibleY = this.contentOffset.y + visibleFrameTop;
186
+ let lastVisibleY = this.contentOffset.y + visibleFrameBottom;
187
+ const paddingPx = viewportHeight / pageScale * paddingRatio;
188
+ firstVisibleY = Math.max(0, firstVisibleY - paddingPx);
189
+ lastVisibleY = lastVisibleY + paddingPx;
297
190
  const numberOfRows = this.numberOfRows();
298
191
  if (this.allRowsHaveEqualHeight) {
299
192
  const rowHeight = this.heightForRowWithIndex(0);
300
- let firstIndex = firstVisibleY / rowHeight;
301
- let lastIndex = lastVisibleY / rowHeight;
302
- firstIndex = Math.trunc(firstIndex);
303
- lastIndex = Math.trunc(lastIndex) + 1;
193
+ let firstIndex = Math.floor(firstVisibleY / rowHeight);
194
+ let lastIndex = Math.floor(lastVisibleY / rowHeight);
304
195
  firstIndex = Math.max(firstIndex, 0);
305
196
  lastIndex = Math.min(lastIndex, numberOfRows - 1);
306
197
  const result2 = [];
307
- for (let i = firstIndex; i < lastIndex + 1; i++) {
198
+ for (let i = firstIndex; i <= lastIndex; i++) {
308
199
  result2.push(i);
309
200
  }
310
201
  return result2;
311
202
  }
312
- let accumulatedHeight = 0;
313
- const result = [];
314
203
  this._calculateAllPositions();
315
204
  const rowPositions = this._rowPositions;
205
+ const result = [];
316
206
  for (let i = 0; i < numberOfRows; i++) {
317
- const height = rowPositions[i].bottomY - rowPositions[i].topY;
318
- accumulatedHeight = accumulatedHeight + height;
319
- if (accumulatedHeight >= firstVisibleY) {
207
+ const position = rowPositions[i];
208
+ if (!position) {
209
+ break;
210
+ }
211
+ const rowTop = position.topY;
212
+ const rowBottom = position.bottomY;
213
+ if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {
320
214
  result.push(i);
321
215
  }
322
- if (accumulatedHeight >= lastVisibleY) {
216
+ if (rowTop > lastVisibleY) {
323
217
  break;
324
218
  }
325
219
  }
@@ -355,11 +249,26 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
355
249
  this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row);
356
250
  }
357
251
  }
252
+ _scheduleDrawVisibleRows() {
253
+ if (!this._isDrawVisibleRowsScheduled) {
254
+ this._isDrawVisibleRowsScheduled = import_UIObject.YES;
255
+ import_UIView.UIView.runFunctionBeforeNextFrame(() => {
256
+ this._calculateAllPositions();
257
+ this._drawVisibleRows();
258
+ this.setNeedsLayout();
259
+ this._isDrawVisibleRowsScheduled = import_UIObject.NO;
260
+ });
261
+ }
262
+ }
358
263
  _drawVisibleRows() {
359
264
  if (!this.isMemberOfViewTree) {
360
265
  return;
361
266
  }
362
267
  const visibleIndexes = this.indexesForVisibleRows();
268
+ if (visibleIndexes.length === 0) {
269
+ this._removeVisibleRows();
270
+ return;
271
+ }
363
272
  const minIndex = visibleIndexes[0];
364
273
  const maxIndex = visibleIndexes[visibleIndexes.length - 1];
365
274
  const removedViews = [];
@@ -450,28 +359,23 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
450
359
  }
451
360
  didScrollToPosition(offsetPosition) {
452
361
  super.didScrollToPosition(offsetPosition);
453
- if (this._useViewportScrolling) {
454
- return;
455
- }
456
- this.forEachViewInSubtree(function(view) {
362
+ this.forEachViewInSubtree((view) => {
457
363
  view._isPointerValid = import_UIObject.NO;
458
364
  });
459
- if (!this._isDrawVisibleRowsScheduled) {
460
- this._isDrawVisibleRowsScheduled = import_UIObject.YES;
461
- import_UIView.UIView.runFunctionBeforeNextFrame(() => {
462
- this._calculateAllPositions();
463
- this._drawVisibleRows();
464
- this.setNeedsLayout();
465
- this._isDrawVisibleRowsScheduled = import_UIObject.NO;
466
- });
365
+ this._scheduleDrawVisibleRows();
366
+ }
367
+ willMoveToSuperview(superview) {
368
+ super.willMoveToSuperview(superview);
369
+ if ((0, import_UIObject.IS)(superview)) {
370
+ this._setupViewportScrollAndResizeHandlersIfNeeded();
371
+ } else {
372
+ this._cleanupViewportScrollListeners();
467
373
  }
468
374
  }
469
375
  wasAddedToViewTree() {
470
376
  super.wasAddedToViewTree();
471
377
  this.loadData();
472
- if (!this._useViewportScrolling) {
473
- this._autoDetectScrollMode();
474
- }
378
+ this._setupViewportScrollAndResizeHandlersIfNeeded();
475
379
  }
476
380
  wasRemovedFromViewTree() {
477
381
  super.wasRemovedFromViewTree();
@@ -503,14 +407,7 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
503
407
  row.style.left = "" + this.sidePadding.integerValue + "px";
504
408
  this.viewHTMLElement.appendChild(row.viewHTMLElement);
505
409
  });
506
- if (this._useViewportScrolling) {
507
- this._fullHeightView.hidden = import_UIObject.NO;
508
- this._fullHeightView.style.position = "absolute";
509
- this._fullHeightView.style.pointerEvents = "none";
510
- this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || import_UIObject.nil).bottomY).rectangleWithWidth(1);
511
- } else {
512
- this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || import_UIObject.nil).bottomY).rectangleWithWidth(bounds.width * 0.5);
513
- }
410
+ this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || import_UIObject.nil).bottomY).rectangleWithWidth(bounds.width * 0.5);
514
411
  this._firstLayoutVisibleRows = [];
515
412
  }
516
413
  _animateLayoutAllRows() {
@@ -527,14 +424,12 @@ class UITableView extends import_UINativeScrollView.UINativeScrollView {
527
424
  );
528
425
  }
529
426
  layoutSubviews() {
530
- const previousPositions = JSON.parse(JSON.stringify(this._rowPositions));
427
+ const previousPositions = JSON.parse(
428
+ JSON.stringify(this._rowPositions)
429
+ );
531
430
  const previousVisibleRowsLength = this._visibleRows.length;
532
431
  if (this._needsDrawingOfVisibleRowsBeforeLayout) {
533
- if (this._useViewportScrolling) {
534
- this._drawVisibleRowsInViewport();
535
- } else {
536
- this._drawVisibleRows();
537
- }
432
+ this._drawVisibleRows();
538
433
  this._needsDrawingOfVisibleRowsBeforeLayout = import_UIObject.NO;
539
434
  }
540
435
  super.layoutSubviews();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../scripts/UITableView.ts"],
4
- "sourcesContent": ["import { UIButton } from \"./UIButton\"\nimport { UINativeScrollView } from \"./UINativeScrollView\"\nimport { FIRST_OR_NIL, IS, IS_DEFINED, nil, NO, YES } from \"./UIObject\"\nimport { UIPoint } from \"./UIPoint\"\nimport { UIRectangle } from \"./UIRectangle\"\nimport { UIView, UIViewBroadcastEvent } from \"./UIView\"\n\n\ninterface UITableViewRowView extends UIView {\n \n _UITableViewRowIndex?: number;\n \n}\n\n\nexport interface UITableViewReusableViewsContainerObject {\n \n [key: string]: UIView[];\n \n}\n\n\nexport interface UITableViewReusableViewPositionObject {\n \n bottomY: number;\n topY: number;\n \n isValid: boolean;\n \n}\n\n\nexport class UITableView extends UINativeScrollView {\n \n \n allRowsHaveEqualHeight: boolean = NO\n _visibleRows: UITableViewRowView[] = []\n _firstLayoutVisibleRows: UITableViewRowView[] = []\n \n _rowPositions: UITableViewReusableViewPositionObject[] = []\n \n _highestValidRowPositionIndex: number = 0\n \n _reusableViews: UITableViewReusableViewsContainerObject = {}\n _removedReusableViews: UITableViewReusableViewsContainerObject = {}\n \n _fullHeightView: UIView\n _rowIDIndex: number = 0\n reloadsOnLanguageChange = YES\n sidePadding = 0\n \n cellWeights?: number[]\n \n _persistedData: any[] = []\n _needsDrawingOfVisibleRowsBeforeLayout = NO\n _isDrawVisibleRowsScheduled = NO\n _shouldAnimateNextLayout?: boolean\n \n override usesVirtualLayoutingForIntrinsicSizing = NO\n \n override animationDuration = 0.25\n \n // Viewport scrolling properties\n private _useViewportScrolling = NO\n private _windowScrollHandler?: () => void\n private _resizeHandler?: () => void\n private _intersectionObserver?: IntersectionObserver\n \n \n constructor(elementID?: string) {\n \n super(elementID)\n \n this._fullHeightView = new UIView()\n this._fullHeightView.hidden = YES\n this._fullHeightView.userInteractionEnabled = NO\n this.addSubview(this._fullHeightView)\n \n this.scrollsX = NO\n \n // Automatically detect if we should use viewport scrolling\n this._autoDetectScrollMode()\n \n }\n \n \n /**\n * Automatically detect if this table should use viewport scrolling\n * If the table's bounds height is >= the total content height,\n * then it doesn't need internal scrolling and should use viewport scrolling\n */\n private _autoDetectScrollMode() {\n // Run detection after the view is added to the tree and layout has occurred\n const checkScrollMode = () => {\n if (!this.isMemberOfViewTree) {\n return\n }\n \n this._calculateAllPositions()\n \n const totalContentHeight = this._rowPositions.length > 0\n ? this._rowPositions[this._rowPositions.length - 1].bottomY\n : 0\n \n const tableBoundsHeight = this.bounds.height\n \n // If the table's height can contain all content, use viewport scrolling\n if (tableBoundsHeight >= totalContentHeight) {\n this.enableViewportBasedVirtualScrolling()\n }\n }\n \n // Check after first layout\n UIView.runFunctionBeforeNextFrame(checkScrollMode)\n }\n \n \n /**\n * Enable viewport-based virtual scrolling for full-height tables\n * This allows the table to be part of the page flow while still\n * benefiting from virtual scrolling performance\n */\n enableViewportBasedVirtualScrolling() {\n if (this._useViewportScrolling) {\n return // Already enabled\n }\n \n this._useViewportScrolling = YES\n this.scrollsX = NO\n this.scrollsY = NO\n \n // No style changes - respect the absolute positioning system\n \n this._setupViewportScrollListeners()\n }\n \n \n /**\n * Disable viewport scrolling and return to normal scroll behavior\n */\n disableViewportBasedVirtualScrolling() {\n if (!this._useViewportScrolling) {\n return\n }\n \n this._useViewportScrolling = NO\n this.scrollsY = YES\n \n this._cleanupViewportScrollListeners()\n }\n \n \n private _setupViewportScrollListeners() {\n this._windowScrollHandler = () => {\n this._scheduleDrawVisibleRowsInViewport()\n }\n \n this._resizeHandler = () => {\n // Invalidate all row positions on resize as widths may have changed\n this._rowPositions.forEach(pos => pos.isValid = NO)\n this._highestValidRowPositionIndex = -1\n this._scheduleDrawVisibleRowsInViewport()\n }\n \n window.addEventListener('scroll', this._windowScrollHandler, { passive: true })\n window.addEventListener('resize', this._resizeHandler, { passive: true })\n \n // Use IntersectionObserver to detect when table enters/exits viewport\n this._intersectionObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n this._scheduleDrawVisibleRowsInViewport()\n }\n })\n },\n {\n root: null,\n rootMargin: '100% 0px', // Load rows 100% viewport height before/after\n threshold: 0\n }\n )\n \n this._intersectionObserver.observe(this.viewHTMLElement)\n }\n \n \n private _cleanupViewportScrollListeners() {\n if (this._windowScrollHandler) {\n window.removeEventListener('scroll', this._windowScrollHandler)\n this._windowScrollHandler = undefined\n }\n \n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler)\n this._resizeHandler = undefined\n }\n \n if (this._intersectionObserver) {\n this._intersectionObserver.disconnect()\n this._intersectionObserver = undefined\n }\n }\n \n \n private _scheduleDrawVisibleRowsInViewport() {\n if (!this._isDrawVisibleRowsScheduled) {\n this._isDrawVisibleRowsScheduled = YES\n \n UIView.runFunctionBeforeNextFrame(() => {\n this._calculateAllPositions()\n this._drawVisibleRowsInViewport()\n this.setNeedsLayout()\n this._isDrawVisibleRowsScheduled = NO\n })\n }\n }\n \n \n /**\n * Calculate which rows are visible in the browser viewport\n * rather than in the scrollview's content area\n */\n indexesForVisibleRowsInViewport(paddingRatio = 0.5): number[] {\n const tableRect = this.viewHTMLElement.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const pageScale = UIView.pageScale\n \n // Calculate which part of the table is visible in viewport\n // Account for page scale when converting from screen to content coordinates\n const visibleTop = Math.max(0, -tableRect.top / pageScale)\n const visibleBottom = Math.min(tableRect.height / pageScale, (viewportHeight - tableRect.top) / pageScale)\n \n // Add padding to render rows slightly before they enter viewport\n const paddingPx = (viewportHeight / pageScale) * paddingRatio\n const firstVisibleY = Math.max(0, visibleTop - paddingPx)\n const lastVisibleY = Math.min(tableRect.height / pageScale, visibleBottom + paddingPx)\n \n const numberOfRows = this.numberOfRows()\n \n if (this.allRowsHaveEqualHeight) {\n const rowHeight = this.heightForRowWithIndex(0)\n \n let firstIndex = Math.floor(firstVisibleY / rowHeight)\n let lastIndex = Math.floor(lastVisibleY / rowHeight)\n \n firstIndex = Math.max(firstIndex, 0)\n lastIndex = Math.min(lastIndex, numberOfRows - 1)\n \n const result = []\n for (let i = firstIndex; i <= lastIndex; i++) {\n result.push(i)\n }\n return result\n }\n \n // Variable height rows\n this._calculateAllPositions()\n \n const rowPositions = this._rowPositions\n const result = []\n \n for (let i = 0; i < numberOfRows; i++) {\n const position = rowPositions[i]\n if (!position) break\n \n const rowTop = position.topY\n const rowBottom = position.bottomY\n \n // Check if row intersects with visible area\n if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {\n result.push(i)\n }\n \n // Early exit if we've passed the visible area\n if (rowTop > lastVisibleY) {\n break\n }\n }\n \n return result\n }\n \n \n /**\n * Draw visible rows based on viewport position\n */\n private _drawVisibleRowsInViewport() {\n if (!this.isMemberOfViewTree) {\n return\n }\n \n const visibleIndexes = this.indexesForVisibleRowsInViewport()\n \n const minIndex = visibleIndexes[0]\n const maxIndex = visibleIndexes[visibleIndexes.length - 1]\n \n const removedViews: UITableViewRowView[] = []\n \n const visibleRows: UITableViewRowView[] = []\n this._visibleRows.forEach((row) => {\n if (IS_DEFINED(row._UITableViewRowIndex) &&\n (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {\n \n this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex,\n row\n )\n \n this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)\n removedViews.push(row)\n }\n else {\n visibleRows.push(row)\n }\n })\n this._visibleRows = visibleRows\n \n visibleIndexes.forEach((rowIndex: number) => {\n if (this.isRowWithIndexVisible(rowIndex)) {\n return\n }\n const view: UITableViewRowView = this.viewForRowWithIndex(rowIndex)\n this._firstLayoutVisibleRows.push(view)\n this._visibleRows.push(view)\n this.addSubview(view)\n })\n \n for (let i = 0; i < removedViews.length; i++) {\n const view = removedViews[i]\n if (this._visibleRows.indexOf(view) == -1) {\n view.removeFromSuperview()\n }\n }\n }\n \n \n loadData() {\n \n this._persistedData = []\n \n this._calculatePositionsUntilIndex(this.numberOfRows() - 1)\n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n this.setNeedsLayout()\n \n }\n \n reloadData() {\n \n this._removeVisibleRows()\n this._removeAllReusableRows()\n \n this._rowPositions = []\n this._highestValidRowPositionIndex = 0\n \n this.loadData()\n \n }\n \n \n highlightChanges(previousData: any[], newData: any[]) {\n \n previousData = previousData.map(dataPoint => JSON.stringify(dataPoint))\n newData = newData.map(dataPoint => JSON.stringify(dataPoint))\n \n const newIndexes: number[] = []\n \n newData.forEach((value, index) => {\n \n if (!previousData.contains(value)) {\n \n newIndexes.push(index)\n \n }\n \n })\n \n newIndexes.forEach(index => {\n \n if (this.isRowWithIndexVisible(index)) {\n this.highlightRowAsNew(this.visibleRowWithIndex(index) as UIView)\n }\n \n })\n \n }\n \n \n highlightRowAsNew(row: UIView) {\n \n \n }\n \n \n invalidateSizeOfRowWithIndex(index: number, animateChange = NO) {\n \n if (this._rowPositions[index]) {\n this._rowPositions[index].isValid = NO\n }\n \n this._highestValidRowPositionIndex = Math.min(this._highestValidRowPositionIndex, index - 1)\n \n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n this._shouldAnimateNextLayout = animateChange\n \n }\n \n \n _calculateAllPositions() {\n this._calculatePositionsUntilIndex(this.numberOfRows() - 1)\n }\n \n _calculatePositionsUntilIndex(maxIndex: number) {\n \n let validPositionObject = this._rowPositions[this._highestValidRowPositionIndex]\n if (!IS(validPositionObject)) {\n validPositionObject = {\n bottomY: 0,\n topY: 0,\n isValid: YES\n }\n }\n \n let previousBottomY = validPositionObject.bottomY\n \n if (!this._rowPositions.length) {\n \n this._highestValidRowPositionIndex = -1\n \n }\n \n for (let i = this._highestValidRowPositionIndex + 1; i <= maxIndex; i++) {\n \n let height: number\n \n const rowPositionObject = this._rowPositions[i]\n \n if (IS((rowPositionObject || nil).isValid)) {\n \n height = rowPositionObject.bottomY - rowPositionObject.topY\n \n }\n else {\n \n height = this.heightForRowWithIndex(i)\n \n }\n \n \n const positionObject: UITableViewReusableViewPositionObject = {\n bottomY: previousBottomY + height,\n topY: previousBottomY,\n isValid: YES\n }\n \n if (i < this._rowPositions.length) {\n this._rowPositions[i] = positionObject\n }\n else {\n this._rowPositions.push(positionObject)\n }\n this._highestValidRowPositionIndex = i\n previousBottomY = previousBottomY + height\n \n }\n \n }\n \n \n indexesForVisibleRows(paddingRatio = 0.5): number[] {\n \n // If using viewport scrolling, delegate to viewport method\n if (this._useViewportScrolling) {\n return this.indexesForVisibleRowsInViewport(paddingRatio)\n }\n \n // Original scroll-based logic\n const firstVisibleY = this.contentOffset.y - this.bounds.height * paddingRatio\n const lastVisibleY = firstVisibleY + this.bounds.height * (1 + paddingRatio)\n \n const numberOfRows = this.numberOfRows()\n \n if (this.allRowsHaveEqualHeight) {\n \n const rowHeight = this.heightForRowWithIndex(0)\n \n let firstIndex = firstVisibleY / rowHeight\n let lastIndex = lastVisibleY / rowHeight\n \n firstIndex = Math.trunc(firstIndex)\n lastIndex = Math.trunc(lastIndex) + 1\n \n firstIndex = Math.max(firstIndex, 0)\n lastIndex = Math.min(lastIndex, numberOfRows - 1)\n \n const result = []\n for (let i = firstIndex; i < lastIndex + 1; i++) {\n result.push(i)\n }\n return result\n }\n \n let accumulatedHeight = 0\n const result = []\n \n this._calculateAllPositions()\n \n const rowPositions = this._rowPositions\n \n for (let i = 0; i < numberOfRows; i++) {\n \n const height = rowPositions[i].bottomY - rowPositions[i].topY\n \n accumulatedHeight = accumulatedHeight + height\n if (accumulatedHeight >= firstVisibleY) {\n result.push(i)\n }\n if (accumulatedHeight >= lastVisibleY) {\n break\n }\n \n }\n \n return result\n \n }\n \n \n _removeVisibleRows() {\n \n const visibleRows: UITableViewRowView[] = []\n this._visibleRows.forEach((row: UIView) => {\n \n this._persistedData[row._UITableViewRowIndex as number] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex as number,\n row\n )\n row.removeFromSuperview()\n this._removedReusableViews[row?._UITableViewReusabilityIdentifier]?.push(row)\n \n \n })\n this._visibleRows = visibleRows\n \n }\n \n \n _removeAllReusableRows() {\n this._reusableViews.forEach((rows: UIView[]) =>\n rows.forEach((row: UIView) => {\n \n this._persistedData[row._UITableViewRowIndex as number] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex as number,\n row\n )\n row.removeFromSuperview()\n \n this._markReusableViewAsUnused(row)\n \n })\n )\n }\n \n \n _markReusableViewAsUnused(row: UIView) {\n if (!this._removedReusableViews[row._UITableViewReusabilityIdentifier].contains(row)) {\n this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)\n }\n }\n \n _drawVisibleRows() {\n \n if (!this.isMemberOfViewTree) {\n return\n }\n \n const visibleIndexes = this.indexesForVisibleRows()\n \n const minIndex = visibleIndexes[0]\n const maxIndex = visibleIndexes[visibleIndexes.length - 1]\n \n const removedViews: UITableViewRowView[] = []\n \n const visibleRows: UITableViewRowView[] = []\n this._visibleRows.forEach((row) => {\n if (IS_DEFINED(row._UITableViewRowIndex) && (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {\n \n this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex,\n row\n )\n \n this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)\n \n removedViews.push(row)\n \n }\n else {\n visibleRows.push(row)\n }\n })\n this._visibleRows = visibleRows\n \n visibleIndexes.forEach((rowIndex: number) => {\n \n if (this.isRowWithIndexVisible(rowIndex)) {\n return\n }\n const view: UITableViewRowView = this.viewForRowWithIndex(rowIndex)\n this._firstLayoutVisibleRows.push(view)\n this._visibleRows.push(view)\n this.addSubview(view)\n \n })\n \n for (let i = 0; i < removedViews.length; i++) {\n \n const view = removedViews[i]\n if (this._visibleRows.indexOf(view) == -1) {\n \n view.removeFromSuperview()\n \n }\n \n }\n \n }\n \n \n visibleRowWithIndex(rowIndex: number | undefined): UIView {\n for (let i = 0; i < this._visibleRows.length; i++) {\n const row = this._visibleRows[i]\n if (row._UITableViewRowIndex == rowIndex) {\n return row\n }\n }\n return nil\n }\n \n \n isRowWithIndexVisible(rowIndex: number) {\n return IS(this.visibleRowWithIndex(rowIndex))\n }\n \n \n reusableViewForIdentifier(identifier: string, rowIndex: number): UITableViewRowView {\n \n if (!this._removedReusableViews[identifier]) {\n this._removedReusableViews[identifier] = []\n }\n \n if (this._removedReusableViews[identifier] && this._removedReusableViews[identifier].length) {\n \n const view = this._removedReusableViews[identifier].pop() as UITableViewRowView\n view._UITableViewRowIndex = rowIndex\n Object.assign(view, this._persistedData[rowIndex] || this.defaultRowPersistenceDataItem())\n return view\n \n }\n \n if (!this._reusableViews[identifier]) {\n this._reusableViews[identifier] = []\n }\n \n const newView = this.newReusableViewForIdentifier(identifier, this._rowIDIndex) as UITableViewRowView\n this._rowIDIndex = this._rowIDIndex + 1\n \n newView._UITableViewReusabilityIdentifier = identifier\n newView._UITableViewRowIndex = rowIndex\n \n Object.assign(newView, this._persistedData[rowIndex] || this.defaultRowPersistenceDataItem())\n this._reusableViews[identifier].push(newView)\n \n return newView\n \n }\n \n \n // Functions that should be overridden to draw the correct content START\n newReusableViewForIdentifier(identifier: string, rowIDIndex: number): UIView {\n \n const view = new UIButton(this.elementID + \"Row\" + rowIDIndex)\n \n view.stopsPointerEventPropagation = NO\n view.pausesPointerEvents = NO\n \n return view\n \n }\n \n heightForRowWithIndex(index: number): number {\n return 50\n }\n \n numberOfRows() {\n return 10000\n }\n \n defaultRowPersistenceDataItem(): any {\n \n \n }\n \n persistenceDataItemForRowWithIndex(rowIndex: number, row: UIView): any {\n \n \n }\n \n viewForRowWithIndex(rowIndex: number): UITableViewRowView {\n const row = this.reusableViewForIdentifier(\"Row\", rowIndex)\n row._UITableViewRowIndex = rowIndex\n FIRST_OR_NIL((row as unknown as UIButton).titleLabel).text = \"Row \" + rowIndex\n return row\n }\n \n // Functions that should be overridden to draw the correct content END\n \n \n // Functions that trigger redrawing of the content\n override didScrollToPosition(offsetPosition: UIPoint) {\n \n super.didScrollToPosition(offsetPosition)\n \n // Skip if using viewport scrolling\n if (this._useViewportScrolling) {\n return\n }\n \n this.forEachViewInSubtree(function (view: UIView) {\n \n view._isPointerValid = NO\n \n })\n \n if (!this._isDrawVisibleRowsScheduled) {\n \n this._isDrawVisibleRowsScheduled = YES\n \n UIView.runFunctionBeforeNextFrame(() => {\n \n this._calculateAllPositions()\n \n this._drawVisibleRows()\n \n this.setNeedsLayout()\n \n this._isDrawVisibleRowsScheduled = NO\n \n })\n \n }\n \n }\n \n override wasAddedToViewTree() {\n super.wasAddedToViewTree()\n this.loadData()\n \n // Re-check scroll mode in case CSS was applied after construction\n if (!this._useViewportScrolling) {\n this._autoDetectScrollMode()\n }\n }\n \n override wasRemovedFromViewTree() {\n super.wasRemovedFromViewTree()\n this._cleanupViewportScrollListeners()\n }\n \n override setFrame(rectangle: UIRectangle, zIndex?: number, performUncheckedLayout?: boolean) {\n \n const frame = this.frame\n super.setFrame(rectangle, zIndex, performUncheckedLayout)\n if (frame.isEqualTo(rectangle) && !performUncheckedLayout) {\n return\n }\n \n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n }\n \n \n override didReceiveBroadcastEvent(event: UIViewBroadcastEvent) {\n \n super.didReceiveBroadcastEvent(event)\n \n if (event.name == UIView.broadcastEventName.LanguageChanged && this.reloadsOnLanguageChange) {\n \n this.reloadData()\n \n }\n \n \n }\n \n \n private _layoutAllRows(positions = this._rowPositions) {\n \n const bounds = this.bounds\n \n this._visibleRows.sort((rowA, rowB) => rowA._UITableViewRowIndex! - rowB._UITableViewRowIndex!)\n .forEach(row => {\n \n const frame = bounds.copy()\n \n const positionObject = positions[row._UITableViewRowIndex!]\n frame.min.y = positionObject.topY\n frame.max.y = positionObject.bottomY\n row.frame = frame\n \n row.style.width = \"\" + (bounds.width - this.sidePadding * 2).integerValue + \"px\"\n row.style.left = \"\" + this.sidePadding.integerValue + \"px\"\n \n // This is to reorder the elements in the DOM\n this.viewHTMLElement.appendChild(row.viewHTMLElement)\n \n })\n \n // For viewport scrolling, the full height view needs to establish the total height\n if (this._useViewportScrolling) {\n this._fullHeightView.hidden = NO\n this._fullHeightView.style.position = 'absolute'\n this._fullHeightView.style.pointerEvents = 'none'\n this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || nil).bottomY)\n .rectangleWithWidth(1) // Minimal width\n } else {\n this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || nil).bottomY)\n .rectangleWithWidth(bounds.width * 0.5)\n }\n \n this._firstLayoutVisibleRows = []\n \n }\n \n private _animateLayoutAllRows() {\n \n UIView.animateViewOrViewsWithDurationDelayAndFunction(\n this._visibleRows,\n this.animationDuration,\n 0,\n undefined,\n () => {\n \n this._layoutAllRows()\n \n },\n () => {\n \n \n }\n )\n \n }\n \n \n override layoutSubviews() {\n \n const previousPositions: UITableViewReusableViewPositionObject[] = JSON.parse(JSON.stringify(this._rowPositions))\n \n const previousVisibleRowsLength = this._visibleRows.length\n \n if (this._needsDrawingOfVisibleRowsBeforeLayout) {\n \n if (this._useViewportScrolling) {\n this._drawVisibleRowsInViewport()\n } else {\n this._drawVisibleRows()\n }\n \n this._needsDrawingOfVisibleRowsBeforeLayout = NO\n \n }\n \n \n super.layoutSubviews()\n \n \n if (!this.numberOfRows() || !this.isMemberOfViewTree) {\n \n return\n \n }\n \n \n if (this._shouldAnimateNextLayout) {\n \n \n // Need to do layout with the previous positions\n \n this._layoutAllRows(previousPositions)\n \n \n if (previousVisibleRowsLength < this._visibleRows.length) {\n \n \n UIView.runFunctionBeforeNextFrame(() => {\n \n this._animateLayoutAllRows()\n \n })\n \n }\n else {\n \n this._animateLayoutAllRows()\n \n }\n \n \n this._shouldAnimateNextLayout = NO\n \n }\n else {\n \n this._calculateAllPositions()\n \n this._layoutAllRows()\n \n \n }\n \n \n }\n \n \n override intrinsicContentHeight(constrainingWidth = 0) {\n \n \n let result = 0\n \n this._calculateAllPositions()\n \n if (this._rowPositions.length) {\n \n result = this._rowPositions[this._rowPositions.length - 1].bottomY\n \n }\n \n return result\n \n }\n \n \n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { UIButton } from \"./UIButton\"\nimport { UINativeScrollView } from \"./UINativeScrollView\"\nimport { FIRST_OR_NIL, IS, IS_DEFINED, nil, NO, YES } from \"./UIObject\"\nimport { UIPoint } from \"./UIPoint\"\nimport { UIRectangle } from \"./UIRectangle\"\nimport { UIView, UIViewBroadcastEvent } from \"./UIView\"\n\n\ninterface UITableViewRowView extends UIView {\n \n _UITableViewRowIndex?: number;\n \n}\n\n\nexport interface UITableViewReusableViewsContainerObject {\n \n [key: string]: UIView[];\n \n}\n\n\nexport interface UITableViewReusableViewPositionObject {\n \n bottomY: number;\n topY: number;\n \n isValid: boolean;\n \n}\n\n\nexport class UITableView extends UINativeScrollView {\n \n \n allRowsHaveEqualHeight: boolean = NO\n _visibleRows: UITableViewRowView[] = []\n _firstLayoutVisibleRows: UITableViewRowView[] = []\n \n _rowPositions: UITableViewReusableViewPositionObject[] = []\n \n _highestValidRowPositionIndex: number = 0\n \n _reusableViews: UITableViewReusableViewsContainerObject = {}\n _removedReusableViews: UITableViewReusableViewsContainerObject = {}\n \n _fullHeightView: UIView\n _rowIDIndex: number = 0\n reloadsOnLanguageChange = YES\n sidePadding = 0\n \n cellWeights?: number[]\n \n _persistedData: any[] = []\n _needsDrawingOfVisibleRowsBeforeLayout = NO\n _isDrawVisibleRowsScheduled = NO\n _shouldAnimateNextLayout?: boolean\n \n override usesVirtualLayoutingForIntrinsicSizing = NO\n \n override animationDuration = 0.25\n \n // Viewport scrolling properties\n _intersectionObserver?: IntersectionObserver\n \n \n constructor(elementID?: string) {\n \n super(elementID)\n \n this._fullHeightView = new UIView()\n this._fullHeightView.hidden = YES\n this._fullHeightView.userInteractionEnabled = NO\n this.addSubview(this._fullHeightView)\n \n this.scrollsX = NO\n \n this._setupViewportScrollAndResizeHandlersIfNeeded()\n \n }\n \n \n _windowScrollHandler = () => {\n if (!this.isMemberOfViewTree) {\n return\n }\n this._scheduleDrawVisibleRows()\n }\n \n _resizeHandler = () => {\n if (!this.isMemberOfViewTree) {\n return\n }\n // Invalidate all row positions on resize as widths may have changed\n this._rowPositions.everyElement.isValid = NO\n this._highestValidRowPositionIndex = -1\n this._scheduleDrawVisibleRows()\n }\n \n _setupViewportScrollAndResizeHandlersIfNeeded() {\n if (this._intersectionObserver) {\n return\n }\n \n window.addEventListener(\"scroll\", this._windowScrollHandler, { passive: true })\n window.addEventListener(\"resize\", this._resizeHandler, { passive: true })\n \n // Use IntersectionObserver to detect when table enters/exits viewport\n this._intersectionObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting && this.isMemberOfViewTree) {\n this._scheduleDrawVisibleRows()\n }\n })\n },\n {\n root: null,\n rootMargin: \"100% 0px\", // Load rows 100% viewport height before/after\n threshold: 0\n }\n )\n this._intersectionObserver.observe(this.viewHTMLElement)\n }\n \n \n _cleanupViewportScrollListeners() {\n window.removeEventListener(\"scroll\", this._windowScrollHandler)\n window.removeEventListener(\"resize\", this._resizeHandler)\n if (this._intersectionObserver) {\n this._intersectionObserver.disconnect()\n this._intersectionObserver = undefined\n }\n }\n \n \n loadData() {\n \n this._persistedData = []\n \n this._calculatePositionsUntilIndex(this.numberOfRows() - 1)\n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n this.setNeedsLayout()\n \n }\n \n reloadData() {\n \n this._removeVisibleRows()\n this._removeAllReusableRows()\n \n this._rowPositions = []\n this._highestValidRowPositionIndex = 0\n \n this.loadData()\n \n }\n \n \n highlightChanges(previousData: any[], newData: any[]) {\n \n previousData = previousData.map(dataPoint => JSON.stringify(dataPoint))\n newData = newData.map(dataPoint => JSON.stringify(dataPoint))\n \n const newIndexes: number[] = []\n \n newData.forEach((value, index) => {\n \n if (!previousData.contains(value)) {\n \n newIndexes.push(index)\n \n }\n \n })\n \n newIndexes.forEach(index => {\n \n if (this.isRowWithIndexVisible(index)) {\n this.highlightRowAsNew(this.visibleRowWithIndex(index) as UIView)\n }\n \n })\n \n }\n \n \n highlightRowAsNew(row: UIView) {\n \n \n }\n \n \n invalidateSizeOfRowWithIndex(index: number, animateChange = NO) {\n \n if (this._rowPositions[index]) {\n this._rowPositions[index].isValid = NO\n }\n \n this._highestValidRowPositionIndex = Math.min(this._highestValidRowPositionIndex, index - 1)\n \n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n this._shouldAnimateNextLayout = animateChange\n \n }\n \n \n _calculateAllPositions() {\n this._calculatePositionsUntilIndex(this.numberOfRows() - 1)\n }\n \n _calculatePositionsUntilIndex(maxIndex: number) {\n \n let validPositionObject = this._rowPositions[this._highestValidRowPositionIndex]\n if (!IS(validPositionObject)) {\n validPositionObject = {\n bottomY: 0,\n topY: 0,\n isValid: YES\n }\n }\n \n let previousBottomY = validPositionObject.bottomY\n \n if (!this._rowPositions.length) {\n \n this._highestValidRowPositionIndex = -1\n \n }\n \n for (let i = this._highestValidRowPositionIndex + 1; i <= maxIndex; i++) {\n \n let height: number\n \n const rowPositionObject = this._rowPositions[i]\n \n if (IS((rowPositionObject || nil).isValid)) {\n \n height = rowPositionObject.bottomY - rowPositionObject.topY\n \n }\n else {\n \n height = this.heightForRowWithIndex(i)\n \n }\n \n \n const positionObject: UITableViewReusableViewPositionObject = {\n bottomY: previousBottomY + height,\n topY: previousBottomY,\n isValid: YES\n }\n \n if (i < this._rowPositions.length) {\n this._rowPositions[i] = positionObject\n }\n else {\n this._rowPositions.push(positionObject)\n }\n this._highestValidRowPositionIndex = i\n previousBottomY = previousBottomY + height\n \n }\n \n }\n \n \n indexesForVisibleRows(paddingRatio = 0.5): number[] {\n \n // 1. Calculate the visible frame relative to the Table's bounds (0,0 is top-left of the table view)\n // This accounts for the Window viewport clipping the table if it is partially off-screen.\n const tableRect = this.viewHTMLElement.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const pageScale = UIView.pageScale\n \n // The top of the visible window relative to the view's top edge.\n // If tableRect.top is negative, the table is scrolled up and clipped by the window top.\n const visibleFrameTop = Math.max(0, -tableRect.top / pageScale)\n \n // The bottom of the visible window relative to the view's top edge.\n // We clip it to the table's actual bounds height so we don't look past the table content.\n const visibleFrameBottom = Math.min(\n this.bounds.height,\n (viewportHeight - tableRect.top) / pageScale\n )\n \n // If the table is completely off-screen, return empty\n if (visibleFrameBottom <= visibleFrameTop) {\n return []\n }\n \n // 2. Convert to Content Coordinates (Scroll Offset)\n // contentOffset.y is the internal scroll position.\n // If using viewport scrolling (full height), contentOffset.y is typically 0.\n // If using internal scrolling, this shifts the visible frame to the correct content rows.\n let firstVisibleY = this.contentOffset.y + visibleFrameTop\n let lastVisibleY = this.contentOffset.y + visibleFrameBottom\n \n // 3. Apply Padding\n // We calculate padding based on the viewport height to ensure smooth scrolling\n const paddingPx = (viewportHeight / pageScale) * paddingRatio\n firstVisibleY = Math.max(0, firstVisibleY - paddingPx)\n lastVisibleY = lastVisibleY + paddingPx\n \n const numberOfRows = this.numberOfRows()\n \n // 4. Find Indexes\n if (this.allRowsHaveEqualHeight) {\n \n const rowHeight = this.heightForRowWithIndex(0)\n \n let firstIndex = Math.floor(firstVisibleY / rowHeight)\n let lastIndex = Math.floor(lastVisibleY / rowHeight)\n \n firstIndex = Math.max(firstIndex, 0)\n lastIndex = Math.min(lastIndex, numberOfRows - 1)\n \n const result = []\n for (let i = firstIndex; i <= lastIndex; i++) {\n result.push(i)\n }\n return result\n }\n \n // Variable Heights\n this._calculateAllPositions()\n const rowPositions = this._rowPositions\n const result = []\n \n for (let i = 0; i < numberOfRows; i++) {\n \n const position = rowPositions[i]\n if (!position) {\n break\n }\n \n const rowTop = position.topY\n const rowBottom = position.bottomY\n \n // Check intersection\n if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {\n result.push(i)\n }\n \n if (rowTop > lastVisibleY) {\n break\n }\n \n }\n \n return result\n \n }\n \n \n _removeVisibleRows() {\n \n const visibleRows: UITableViewRowView[] = []\n this._visibleRows.forEach((row: UIView) => {\n \n this._persistedData[row._UITableViewRowIndex as number] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex as number,\n row\n )\n row.removeFromSuperview()\n this._removedReusableViews[row?._UITableViewReusabilityIdentifier]?.push(row)\n \n \n })\n this._visibleRows = visibleRows\n \n }\n \n \n _removeAllReusableRows() {\n this._reusableViews.forEach((rows: UIView[]) =>\n rows.forEach((row: UIView) => {\n \n this._persistedData[row._UITableViewRowIndex as number] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex as number,\n row\n )\n row.removeFromSuperview()\n \n this._markReusableViewAsUnused(row)\n \n })\n )\n }\n \n \n _markReusableViewAsUnused(row: UIView) {\n if (!this._removedReusableViews[row._UITableViewReusabilityIdentifier].contains(row)) {\n this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)\n }\n }\n \n _scheduleDrawVisibleRows() {\n if (!this._isDrawVisibleRowsScheduled) {\n this._isDrawVisibleRowsScheduled = YES\n \n UIView.runFunctionBeforeNextFrame(() => {\n this._calculateAllPositions()\n this._drawVisibleRows()\n this.setNeedsLayout()\n this._isDrawVisibleRowsScheduled = NO\n })\n }\n }\n \n _drawVisibleRows() {\n \n if (!this.isMemberOfViewTree) {\n return\n }\n \n // Uses the unified method above\n const visibleIndexes = this.indexesForVisibleRows()\n \n // If no rows are visible, remove all current rows\n if (visibleIndexes.length === 0) {\n this._removeVisibleRows()\n return\n }\n \n const minIndex = visibleIndexes[0]\n const maxIndex = visibleIndexes[visibleIndexes.length - 1]\n \n const removedViews: UITableViewRowView[] = []\n const visibleRows: UITableViewRowView[] = []\n \n // 1. Identify rows that have moved off-screen\n this._visibleRows.forEach((row) => {\n if (IS_DEFINED(row._UITableViewRowIndex) &&\n (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {\n \n // Persist state before removal\n this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(\n row._UITableViewRowIndex,\n row\n )\n \n this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)\n removedViews.push(row)\n }\n else {\n visibleRows.push(row)\n }\n })\n \n this._visibleRows = visibleRows\n \n // 2. Add new rows that have moved on-screen\n visibleIndexes.forEach((rowIndex: number) => {\n if (this.isRowWithIndexVisible(rowIndex)) {\n return\n }\n \n const view: UITableViewRowView = this.viewForRowWithIndex(rowIndex)\n this._firstLayoutVisibleRows.push(view)\n this._visibleRows.push(view)\n this.addSubview(view)\n })\n \n // 3. Clean up DOM\n for (let i = 0; i < removedViews.length; i++) {\n const view = removedViews[i]\n if (this._visibleRows.indexOf(view) == -1) {\n view.removeFromSuperview()\n }\n }\n \n }\n \n \n visibleRowWithIndex(rowIndex: number | undefined): UIView {\n for (let i = 0; i < this._visibleRows.length; i++) {\n const row = this._visibleRows[i]\n if (row._UITableViewRowIndex == rowIndex) {\n return row\n }\n }\n return nil\n }\n \n \n isRowWithIndexVisible(rowIndex: number) {\n return IS(this.visibleRowWithIndex(rowIndex))\n }\n \n \n reusableViewForIdentifier(identifier: string, rowIndex: number): UITableViewRowView {\n \n if (!this._removedReusableViews[identifier]) {\n this._removedReusableViews[identifier] = []\n }\n \n if (this._removedReusableViews[identifier] && this._removedReusableViews[identifier].length) {\n \n const view = this._removedReusableViews[identifier].pop() as UITableViewRowView\n view._UITableViewRowIndex = rowIndex\n Object.assign(view, this._persistedData[rowIndex] || this.defaultRowPersistenceDataItem())\n return view\n \n }\n \n if (!this._reusableViews[identifier]) {\n this._reusableViews[identifier] = []\n }\n \n const newView = this.newReusableViewForIdentifier(identifier, this._rowIDIndex) as UITableViewRowView\n this._rowIDIndex = this._rowIDIndex + 1\n \n newView._UITableViewReusabilityIdentifier = identifier\n newView._UITableViewRowIndex = rowIndex\n \n Object.assign(newView, this._persistedData[rowIndex] || this.defaultRowPersistenceDataItem())\n this._reusableViews[identifier].push(newView)\n \n return newView\n \n }\n \n \n // Functions that should be overridden to draw the correct content START\n newReusableViewForIdentifier(identifier: string, rowIDIndex: number): UIView {\n \n const view = new UIButton(this.elementID + \"Row\" + rowIDIndex)\n \n view.stopsPointerEventPropagation = NO\n view.pausesPointerEvents = NO\n \n return view\n \n }\n \n heightForRowWithIndex(index: number): number {\n return 50\n }\n \n numberOfRows() {\n return 10000\n }\n \n defaultRowPersistenceDataItem(): any {\n \n \n }\n \n persistenceDataItemForRowWithIndex(rowIndex: number, row: UIView): any {\n \n \n }\n \n viewForRowWithIndex(rowIndex: number): UITableViewRowView {\n const row = this.reusableViewForIdentifier(\"Row\", rowIndex)\n row._UITableViewRowIndex = rowIndex\n FIRST_OR_NIL((row as unknown as UIButton).titleLabel).text = \"Row \" + rowIndex\n return row\n }\n \n // Functions that should be overridden to draw the correct content END\n \n \n // Functions that trigger redrawing of the content\n override didScrollToPosition(offsetPosition: UIPoint) {\n \n super.didScrollToPosition(offsetPosition)\n \n this.forEachViewInSubtree((view: UIView) => {\n view._isPointerValid = NO\n })\n \n this._scheduleDrawVisibleRows()\n \n }\n \n override willMoveToSuperview(superview: UIView) {\n super.willMoveToSuperview(superview)\n \n if (IS(superview)) {\n // Set up viewport listeners when added to a superview\n this._setupViewportScrollAndResizeHandlersIfNeeded()\n }\n else {\n // Clean up when removed from superview\n this._cleanupViewportScrollListeners()\n }\n }\n \n override wasAddedToViewTree() {\n super.wasAddedToViewTree()\n this.loadData()\n \n // Ensure listeners are set up\n this._setupViewportScrollAndResizeHandlersIfNeeded()\n \n }\n \n override wasRemovedFromViewTree() {\n super.wasRemovedFromViewTree()\n this._cleanupViewportScrollListeners()\n }\n \n override setFrame(rectangle: UIRectangle, zIndex?: number, performUncheckedLayout?: boolean) {\n \n const frame = this.frame\n super.setFrame(rectangle, zIndex, performUncheckedLayout)\n if (frame.isEqualTo(rectangle) && !performUncheckedLayout) {\n return\n }\n \n this._needsDrawingOfVisibleRowsBeforeLayout = YES\n \n }\n \n \n override didReceiveBroadcastEvent(event: UIViewBroadcastEvent) {\n \n super.didReceiveBroadcastEvent(event)\n \n if (event.name == UIView.broadcastEventName.LanguageChanged && this.reloadsOnLanguageChange) {\n \n this.reloadData()\n \n }\n \n \n }\n \n \n private _layoutAllRows(positions = this._rowPositions) {\n \n const bounds = this.bounds\n \n this._visibleRows.sort((rowA, rowB) => rowA._UITableViewRowIndex! - rowB._UITableViewRowIndex!)\n .forEach(row => {\n \n const frame = bounds.copy()\n \n const positionObject = positions[row._UITableViewRowIndex!]\n frame.min.y = positionObject.topY\n frame.max.y = positionObject.bottomY\n row.frame = frame\n \n row.style.width = \"\" + (bounds.width - this.sidePadding * 2).integerValue + \"px\"\n row.style.left = \"\" + this.sidePadding.integerValue + \"px\"\n \n // This is to reorder the elements in the DOM\n this.viewHTMLElement.appendChild(row.viewHTMLElement)\n \n })\n \n this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement ||\n nil).bottomY).rectangleWithWidth(bounds.width * 0.5)\n \n this._firstLayoutVisibleRows = []\n \n }\n \n private _animateLayoutAllRows() {\n \n UIView.animateViewOrViewsWithDurationDelayAndFunction(\n this._visibleRows,\n this.animationDuration,\n 0,\n undefined,\n () => {\n \n this._layoutAllRows()\n \n },\n () => {\n \n \n }\n )\n \n }\n \n \n override layoutSubviews() {\n \n const previousPositions: UITableViewReusableViewPositionObject[] = JSON.parse(\n JSON.stringify(this._rowPositions))\n \n const previousVisibleRowsLength = this._visibleRows.length\n \n if (this._needsDrawingOfVisibleRowsBeforeLayout) {\n \n this._drawVisibleRows()\n \n this._needsDrawingOfVisibleRowsBeforeLayout = NO\n \n }\n \n \n super.layoutSubviews()\n \n \n if (!this.numberOfRows() || !this.isMemberOfViewTree) {\n \n return\n \n }\n \n \n if (this._shouldAnimateNextLayout) {\n \n \n // Need to do layout with the previous positions\n \n this._layoutAllRows(previousPositions)\n \n \n if (previousVisibleRowsLength < this._visibleRows.length) {\n \n \n UIView.runFunctionBeforeNextFrame(() => {\n \n this._animateLayoutAllRows()\n \n })\n \n }\n else {\n \n this._animateLayoutAllRows()\n \n }\n \n \n this._shouldAnimateNextLayout = NO\n \n }\n else {\n \n this._calculateAllPositions()\n \n this._layoutAllRows()\n \n \n }\n \n \n }\n \n \n override intrinsicContentHeight(constrainingWidth = 0) {\n \n \n let result = 0\n \n this._calculateAllPositions()\n \n if (this._rowPositions.length) {\n \n result = this._rowPositions[this._rowPositions.length - 1].bottomY\n \n }\n \n return result\n \n }\n \n \n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["result"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uicore-ts",
3
- "version": "1.1.102",
3
+ "version": "1.1.105",
4
4
  "description": "UICore is a library to build native-like user interfaces using pure Typescript. No HTML is needed at all. Components are described as TS classes and all user interactions are handled explicitly. This library is strongly inspired by the UIKit framework that is used in IOS. In addition, UICore has tools to handle URL based routing, array sorting and filtering and adds a number of other utilities for convenience.",
5
5
  "main": "compiledScripts/index.js",
6
6
  "types": "compiledScripts/index.d.ts",
@@ -61,10 +61,7 @@ export class UITableView extends UINativeScrollView {
61
61
  override animationDuration = 0.25
62
62
 
63
63
  // Viewport scrolling properties
64
- private _useViewportScrolling = NO
65
- private _windowScrollHandler?: () => void
66
- private _resizeHandler?: () => void
67
- private _intersectionObserver?: IntersectionObserver
64
+ _intersectionObserver?: IntersectionObserver
68
65
 
69
66
 
70
67
  constructor(elementID?: string) {
@@ -78,124 +75,58 @@ export class UITableView extends UINativeScrollView {
78
75
 
79
76
  this.scrollsX = NO
80
77
 
81
- // Automatically detect if we should use viewport scrolling
82
- this._autoDetectScrollMode()
78
+ this._setupViewportScrollAndResizeHandlersIfNeeded()
83
79
 
84
80
  }
85
81
 
86
82
 
87
- /**
88
- * Automatically detect if this table should use viewport scrolling
89
- * If the table's bounds height is >= the total content height,
90
- * then it doesn't need internal scrolling and should use viewport scrolling
91
- */
92
- private _autoDetectScrollMode() {
93
- // Run detection after the view is added to the tree and layout has occurred
94
- const checkScrollMode = () => {
95
- if (!this.isMemberOfViewTree) {
96
- return
97
- }
98
-
99
- this._calculateAllPositions()
100
-
101
- const totalContentHeight = this._rowPositions.length > 0
102
- ? this._rowPositions[this._rowPositions.length - 1].bottomY
103
- : 0
104
-
105
- const tableBoundsHeight = this.bounds.height
106
-
107
- // If the table's height can contain all content, use viewport scrolling
108
- if (tableBoundsHeight >= totalContentHeight) {
109
- this.enableViewportBasedVirtualScrolling()
110
- }
83
+ _windowScrollHandler = () => {
84
+ if (!this.isMemberOfViewTree) {
85
+ return
111
86
  }
112
-
113
- // Check after first layout
114
- UIView.runFunctionBeforeNextFrame(checkScrollMode)
87
+ this._scheduleDrawVisibleRows()
115
88
  }
116
89
 
117
-
118
- /**
119
- * Enable viewport-based virtual scrolling for full-height tables
120
- * This allows the table to be part of the page flow while still
121
- * benefiting from virtual scrolling performance
122
- */
123
- enableViewportBasedVirtualScrolling() {
124
- if (this._useViewportScrolling) {
125
- return // Already enabled
126
- }
127
-
128
- this._useViewportScrolling = YES
129
- this.scrollsX = NO
130
- this.scrollsY = NO
131
-
132
- // No style changes - respect the absolute positioning system
133
-
134
- this._setupViewportScrollListeners()
135
- }
136
-
137
-
138
- /**
139
- * Disable viewport scrolling and return to normal scroll behavior
140
- */
141
- disableViewportBasedVirtualScrolling() {
142
- if (!this._useViewportScrolling) {
90
+ _resizeHandler = () => {
91
+ if (!this.isMemberOfViewTree) {
143
92
  return
144
93
  }
145
-
146
- this._useViewportScrolling = NO
147
- this.scrollsY = YES
148
-
149
- this._cleanupViewportScrollListeners()
94
+ // Invalidate all row positions on resize as widths may have changed
95
+ this._rowPositions.everyElement.isValid = NO
96
+ this._highestValidRowPositionIndex = -1
97
+ this._scheduleDrawVisibleRows()
150
98
  }
151
99
 
152
-
153
- private _setupViewportScrollListeners() {
154
- this._windowScrollHandler = () => {
155
- this._scheduleDrawVisibleRowsInViewport()
156
- }
157
-
158
- this._resizeHandler = () => {
159
- // Invalidate all row positions on resize as widths may have changed
160
- this._rowPositions.forEach(pos => pos.isValid = NO)
161
- this._highestValidRowPositionIndex = -1
162
- this._scheduleDrawVisibleRowsInViewport()
100
+ _setupViewportScrollAndResizeHandlersIfNeeded() {
101
+ if (this._intersectionObserver) {
102
+ return
163
103
  }
164
104
 
165
- window.addEventListener('scroll', this._windowScrollHandler, { passive: true })
166
- window.addEventListener('resize', this._resizeHandler, { passive: true })
105
+ window.addEventListener("scroll", this._windowScrollHandler, { passive: true })
106
+ window.addEventListener("resize", this._resizeHandler, { passive: true })
167
107
 
168
108
  // Use IntersectionObserver to detect when table enters/exits viewport
169
109
  this._intersectionObserver = new IntersectionObserver(
170
110
  (entries) => {
171
111
  entries.forEach(entry => {
172
- if (entry.isIntersecting) {
173
- this._scheduleDrawVisibleRowsInViewport()
112
+ if (entry.isIntersecting && this.isMemberOfViewTree) {
113
+ this._scheduleDrawVisibleRows()
174
114
  }
175
115
  })
176
116
  },
177
117
  {
178
118
  root: null,
179
- rootMargin: '100% 0px', // Load rows 100% viewport height before/after
119
+ rootMargin: "100% 0px", // Load rows 100% viewport height before/after
180
120
  threshold: 0
181
121
  }
182
122
  )
183
-
184
123
  this._intersectionObserver.observe(this.viewHTMLElement)
185
124
  }
186
125
 
187
126
 
188
- private _cleanupViewportScrollListeners() {
189
- if (this._windowScrollHandler) {
190
- window.removeEventListener('scroll', this._windowScrollHandler)
191
- this._windowScrollHandler = undefined
192
- }
193
-
194
- if (this._resizeHandler) {
195
- window.removeEventListener('resize', this._resizeHandler)
196
- this._resizeHandler = undefined
197
- }
198
-
127
+ _cleanupViewportScrollListeners() {
128
+ window.removeEventListener("scroll", this._windowScrollHandler)
129
+ window.removeEventListener("resize", this._resizeHandler)
199
130
  if (this._intersectionObserver) {
200
131
  this._intersectionObserver.disconnect()
201
132
  this._intersectionObserver = undefined
@@ -203,138 +134,6 @@ export class UITableView extends UINativeScrollView {
203
134
  }
204
135
 
205
136
 
206
- private _scheduleDrawVisibleRowsInViewport() {
207
- if (!this._isDrawVisibleRowsScheduled) {
208
- this._isDrawVisibleRowsScheduled = YES
209
-
210
- UIView.runFunctionBeforeNextFrame(() => {
211
- this._calculateAllPositions()
212
- this._drawVisibleRowsInViewport()
213
- this.setNeedsLayout()
214
- this._isDrawVisibleRowsScheduled = NO
215
- })
216
- }
217
- }
218
-
219
-
220
- /**
221
- * Calculate which rows are visible in the browser viewport
222
- * rather than in the scrollview's content area
223
- */
224
- indexesForVisibleRowsInViewport(paddingRatio = 0.5): number[] {
225
- const tableRect = this.viewHTMLElement.getBoundingClientRect()
226
- const viewportHeight = window.innerHeight
227
- const pageScale = UIView.pageScale
228
-
229
- // Calculate which part of the table is visible in viewport
230
- // Account for page scale when converting from screen to content coordinates
231
- const visibleTop = Math.max(0, -tableRect.top / pageScale)
232
- const visibleBottom = Math.min(tableRect.height / pageScale, (viewportHeight - tableRect.top) / pageScale)
233
-
234
- // Add padding to render rows slightly before they enter viewport
235
- const paddingPx = (viewportHeight / pageScale) * paddingRatio
236
- const firstVisibleY = Math.max(0, visibleTop - paddingPx)
237
- const lastVisibleY = Math.min(tableRect.height / pageScale, visibleBottom + paddingPx)
238
-
239
- const numberOfRows = this.numberOfRows()
240
-
241
- if (this.allRowsHaveEqualHeight) {
242
- const rowHeight = this.heightForRowWithIndex(0)
243
-
244
- let firstIndex = Math.floor(firstVisibleY / rowHeight)
245
- let lastIndex = Math.floor(lastVisibleY / rowHeight)
246
-
247
- firstIndex = Math.max(firstIndex, 0)
248
- lastIndex = Math.min(lastIndex, numberOfRows - 1)
249
-
250
- const result = []
251
- for (let i = firstIndex; i <= lastIndex; i++) {
252
- result.push(i)
253
- }
254
- return result
255
- }
256
-
257
- // Variable height rows
258
- this._calculateAllPositions()
259
-
260
- const rowPositions = this._rowPositions
261
- const result = []
262
-
263
- for (let i = 0; i < numberOfRows; i++) {
264
- const position = rowPositions[i]
265
- if (!position) break
266
-
267
- const rowTop = position.topY
268
- const rowBottom = position.bottomY
269
-
270
- // Check if row intersects with visible area
271
- if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {
272
- result.push(i)
273
- }
274
-
275
- // Early exit if we've passed the visible area
276
- if (rowTop > lastVisibleY) {
277
- break
278
- }
279
- }
280
-
281
- return result
282
- }
283
-
284
-
285
- /**
286
- * Draw visible rows based on viewport position
287
- */
288
- private _drawVisibleRowsInViewport() {
289
- if (!this.isMemberOfViewTree) {
290
- return
291
- }
292
-
293
- const visibleIndexes = this.indexesForVisibleRowsInViewport()
294
-
295
- const minIndex = visibleIndexes[0]
296
- const maxIndex = visibleIndexes[visibleIndexes.length - 1]
297
-
298
- const removedViews: UITableViewRowView[] = []
299
-
300
- const visibleRows: UITableViewRowView[] = []
301
- this._visibleRows.forEach((row) => {
302
- if (IS_DEFINED(row._UITableViewRowIndex) &&
303
- (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {
304
-
305
- this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(
306
- row._UITableViewRowIndex,
307
- row
308
- )
309
-
310
- this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)
311
- removedViews.push(row)
312
- }
313
- else {
314
- visibleRows.push(row)
315
- }
316
- })
317
- this._visibleRows = visibleRows
318
-
319
- visibleIndexes.forEach((rowIndex: number) => {
320
- if (this.isRowWithIndexVisible(rowIndex)) {
321
- return
322
- }
323
- const view: UITableViewRowView = this.viewForRowWithIndex(rowIndex)
324
- this._firstLayoutVisibleRows.push(view)
325
- this._visibleRows.push(view)
326
- this.addSubview(view)
327
- })
328
-
329
- for (let i = 0; i < removedViews.length; i++) {
330
- const view = removedViews[i]
331
- if (this._visibleRows.indexOf(view) == -1) {
332
- view.removeFromSuperview()
333
- }
334
- }
335
- }
336
-
337
-
338
137
  loadData() {
339
138
 
340
139
  this._persistedData = []
@@ -471,53 +270,82 @@ export class UITableView extends UINativeScrollView {
471
270
 
472
271
  indexesForVisibleRows(paddingRatio = 0.5): number[] {
473
272
 
474
- // If using viewport scrolling, delegate to viewport method
475
- if (this._useViewportScrolling) {
476
- return this.indexesForVisibleRowsInViewport(paddingRatio)
273
+ // 1. Calculate the visible frame relative to the Table's bounds (0,0 is top-left of the table view)
274
+ // This accounts for the Window viewport clipping the table if it is partially off-screen.
275
+ const tableRect = this.viewHTMLElement.getBoundingClientRect()
276
+ const viewportHeight = window.innerHeight
277
+ const pageScale = UIView.pageScale
278
+
279
+ // The top of the visible window relative to the view's top edge.
280
+ // If tableRect.top is negative, the table is scrolled up and clipped by the window top.
281
+ const visibleFrameTop = Math.max(0, -tableRect.top / pageScale)
282
+
283
+ // The bottom of the visible window relative to the view's top edge.
284
+ // We clip it to the table's actual bounds height so we don't look past the table content.
285
+ const visibleFrameBottom = Math.min(
286
+ this.bounds.height,
287
+ (viewportHeight - tableRect.top) / pageScale
288
+ )
289
+
290
+ // If the table is completely off-screen, return empty
291
+ if (visibleFrameBottom <= visibleFrameTop) {
292
+ return []
477
293
  }
478
294
 
479
- // Original scroll-based logic
480
- const firstVisibleY = this.contentOffset.y - this.bounds.height * paddingRatio
481
- const lastVisibleY = firstVisibleY + this.bounds.height * (1 + paddingRatio)
295
+ // 2. Convert to Content Coordinates (Scroll Offset)
296
+ // contentOffset.y is the internal scroll position.
297
+ // If using viewport scrolling (full height), contentOffset.y is typically 0.
298
+ // If using internal scrolling, this shifts the visible frame to the correct content rows.
299
+ let firstVisibleY = this.contentOffset.y + visibleFrameTop
300
+ let lastVisibleY = this.contentOffset.y + visibleFrameBottom
301
+
302
+ // 3. Apply Padding
303
+ // We calculate padding based on the viewport height to ensure smooth scrolling
304
+ const paddingPx = (viewportHeight / pageScale) * paddingRatio
305
+ firstVisibleY = Math.max(0, firstVisibleY - paddingPx)
306
+ lastVisibleY = lastVisibleY + paddingPx
482
307
 
483
308
  const numberOfRows = this.numberOfRows()
484
309
 
310
+ // 4. Find Indexes
485
311
  if (this.allRowsHaveEqualHeight) {
486
312
 
487
313
  const rowHeight = this.heightForRowWithIndex(0)
488
314
 
489
- let firstIndex = firstVisibleY / rowHeight
490
- let lastIndex = lastVisibleY / rowHeight
491
-
492
- firstIndex = Math.trunc(firstIndex)
493
- lastIndex = Math.trunc(lastIndex) + 1
315
+ let firstIndex = Math.floor(firstVisibleY / rowHeight)
316
+ let lastIndex = Math.floor(lastVisibleY / rowHeight)
494
317
 
495
318
  firstIndex = Math.max(firstIndex, 0)
496
319
  lastIndex = Math.min(lastIndex, numberOfRows - 1)
497
320
 
498
321
  const result = []
499
- for (let i = firstIndex; i < lastIndex + 1; i++) {
322
+ for (let i = firstIndex; i <= lastIndex; i++) {
500
323
  result.push(i)
501
324
  }
502
325
  return result
503
326
  }
504
327
 
505
- let accumulatedHeight = 0
506
- const result = []
507
-
328
+ // Variable Heights
508
329
  this._calculateAllPositions()
509
-
510
330
  const rowPositions = this._rowPositions
331
+ const result = []
511
332
 
512
333
  for (let i = 0; i < numberOfRows; i++) {
513
334
 
514
- const height = rowPositions[i].bottomY - rowPositions[i].topY
335
+ const position = rowPositions[i]
336
+ if (!position) {
337
+ break
338
+ }
339
+
340
+ const rowTop = position.topY
341
+ const rowBottom = position.bottomY
515
342
 
516
- accumulatedHeight = accumulatedHeight + height
517
- if (accumulatedHeight >= firstVisibleY) {
343
+ // Check intersection
344
+ if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {
518
345
  result.push(i)
519
346
  }
520
- if (accumulatedHeight >= lastVisibleY) {
347
+
348
+ if (rowTop > lastVisibleY) {
521
349
  break
522
350
  }
523
351
 
@@ -570,60 +398,79 @@ export class UITableView extends UINativeScrollView {
570
398
  }
571
399
  }
572
400
 
401
+ _scheduleDrawVisibleRows() {
402
+ if (!this._isDrawVisibleRowsScheduled) {
403
+ this._isDrawVisibleRowsScheduled = YES
404
+
405
+ UIView.runFunctionBeforeNextFrame(() => {
406
+ this._calculateAllPositions()
407
+ this._drawVisibleRows()
408
+ this.setNeedsLayout()
409
+ this._isDrawVisibleRowsScheduled = NO
410
+ })
411
+ }
412
+ }
413
+
573
414
  _drawVisibleRows() {
574
415
 
575
416
  if (!this.isMemberOfViewTree) {
576
417
  return
577
418
  }
578
419
 
420
+ // Uses the unified method above
579
421
  const visibleIndexes = this.indexesForVisibleRows()
580
422
 
423
+ // If no rows are visible, remove all current rows
424
+ if (visibleIndexes.length === 0) {
425
+ this._removeVisibleRows()
426
+ return
427
+ }
428
+
581
429
  const minIndex = visibleIndexes[0]
582
430
  const maxIndex = visibleIndexes[visibleIndexes.length - 1]
583
431
 
584
432
  const removedViews: UITableViewRowView[] = []
585
-
586
433
  const visibleRows: UITableViewRowView[] = []
434
+
435
+ // 1. Identify rows that have moved off-screen
587
436
  this._visibleRows.forEach((row) => {
588
- if (IS_DEFINED(row._UITableViewRowIndex) && (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {
437
+ if (IS_DEFINED(row._UITableViewRowIndex) &&
438
+ (row._UITableViewRowIndex < minIndex || row._UITableViewRowIndex > maxIndex)) {
589
439
 
440
+ // Persist state before removal
590
441
  this._persistedData[row._UITableViewRowIndex] = this.persistenceDataItemForRowWithIndex(
591
442
  row._UITableViewRowIndex,
592
443
  row
593
444
  )
594
445
 
595
446
  this._removedReusableViews[row._UITableViewReusabilityIdentifier].push(row)
596
-
597
447
  removedViews.push(row)
598
-
599
448
  }
600
449
  else {
601
450
  visibleRows.push(row)
602
451
  }
603
452
  })
453
+
604
454
  this._visibleRows = visibleRows
605
455
 
456
+ // 2. Add new rows that have moved on-screen
606
457
  visibleIndexes.forEach((rowIndex: number) => {
607
-
608
458
  if (this.isRowWithIndexVisible(rowIndex)) {
609
459
  return
610
460
  }
461
+
611
462
  const view: UITableViewRowView = this.viewForRowWithIndex(rowIndex)
612
463
  this._firstLayoutVisibleRows.push(view)
613
464
  this._visibleRows.push(view)
614
465
  this.addSubview(view)
615
-
616
466
  })
617
467
 
468
+ // 3. Clean up DOM
618
469
  for (let i = 0; i < removedViews.length; i++) {
619
-
620
470
  const view = removedViews[i]
621
471
  if (this._visibleRows.indexOf(view) == -1) {
622
-
623
472
  view.removeFromSuperview()
624
-
625
473
  }
626
-
627
474
  }
628
475
 
629
476
  }
@@ -723,45 +570,34 @@ export class UITableView extends UINativeScrollView {
723
570
 
724
571
  super.didScrollToPosition(offsetPosition)
725
572
 
726
- // Skip if using viewport scrolling
727
- if (this._useViewportScrolling) {
728
- return
729
- }
730
-
731
- this.forEachViewInSubtree(function (view: UIView) {
732
-
573
+ this.forEachViewInSubtree((view: UIView) => {
733
574
  view._isPointerValid = NO
734
-
735
575
  })
736
576
 
737
- if (!this._isDrawVisibleRowsScheduled) {
738
-
739
- this._isDrawVisibleRowsScheduled = YES
740
-
741
- UIView.runFunctionBeforeNextFrame(() => {
742
-
743
- this._calculateAllPositions()
744
-
745
- this._drawVisibleRows()
746
-
747
- this.setNeedsLayout()
748
-
749
- this._isDrawVisibleRowsScheduled = NO
750
-
751
- })
752
-
753
- }
577
+ this._scheduleDrawVisibleRows()
754
578
 
755
579
  }
756
580
 
581
+ override willMoveToSuperview(superview: UIView) {
582
+ super.willMoveToSuperview(superview)
583
+
584
+ if (IS(superview)) {
585
+ // Set up viewport listeners when added to a superview
586
+ this._setupViewportScrollAndResizeHandlersIfNeeded()
587
+ }
588
+ else {
589
+ // Clean up when removed from superview
590
+ this._cleanupViewportScrollListeners()
591
+ }
592
+ }
593
+
757
594
  override wasAddedToViewTree() {
758
595
  super.wasAddedToViewTree()
759
596
  this.loadData()
760
597
 
761
- // Re-check scroll mode in case CSS was applied after construction
762
- if (!this._useViewportScrolling) {
763
- this._autoDetectScrollMode()
764
- }
598
+ // Ensure listeners are set up
599
+ this._setupViewportScrollAndResizeHandlersIfNeeded()
600
+
765
601
  }
766
602
 
767
603
  override wasRemovedFromViewTree() {
@@ -818,17 +654,8 @@ export class UITableView extends UINativeScrollView {
818
654
 
819
655
  })
820
656
 
821
- // For viewport scrolling, the full height view needs to establish the total height
822
- if (this._useViewportScrolling) {
823
- this._fullHeightView.hidden = NO
824
- this._fullHeightView.style.position = 'absolute'
825
- this._fullHeightView.style.pointerEvents = 'none'
826
- this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || nil).bottomY)
827
- .rectangleWithWidth(1) // Minimal width
828
- } else {
829
- this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement || nil).bottomY)
830
- .rectangleWithWidth(bounds.width * 0.5)
831
- }
657
+ this._fullHeightView.frame = bounds.rectangleWithHeight((positions.lastElement ||
658
+ nil).bottomY).rectangleWithWidth(bounds.width * 0.5)
832
659
 
833
660
  this._firstLayoutVisibleRows = []
834
661
 
@@ -857,17 +684,14 @@ export class UITableView extends UINativeScrollView {
857
684
 
858
685
  override layoutSubviews() {
859
686
 
860
- const previousPositions: UITableViewReusableViewPositionObject[] = JSON.parse(JSON.stringify(this._rowPositions))
687
+ const previousPositions: UITableViewReusableViewPositionObject[] = JSON.parse(
688
+ JSON.stringify(this._rowPositions))
861
689
 
862
690
  const previousVisibleRowsLength = this._visibleRows.length
863
691
 
864
692
  if (this._needsDrawingOfVisibleRowsBeforeLayout) {
865
693
 
866
- if (this._useViewportScrolling) {
867
- this._drawVisibleRowsInViewport()
868
- } else {
869
- this._drawVisibleRows()
870
- }
694
+ this._drawVisibleRows()
871
695
 
872
696
  this._needsDrawingOfVisibleRowsBeforeLayout = NO
873
697