uicore-ts 1.1.102 → 1.1.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiledScripts/UIActionIndicator.js.map +2 -2
- package/compiledScripts/UILoadingView.d.ts +21 -0
- package/compiledScripts/UILoadingView.js +144 -0
- package/compiledScripts/UILoadingView.js.map +7 -0
- package/compiledScripts/UIRectangle.d.ts +2 -1
- package/compiledScripts/UIRectangle.js +13 -0
- package/compiledScripts/UIRectangle.js.map +2 -2
- package/compiledScripts/UITableView.d.ts +7 -32
- package/compiledScripts/UITableView.js +77 -182
- package/compiledScripts/UITableView.js.map +2 -2
- package/compiledScripts/UITextView.d.ts +3 -3
- package/compiledScripts/UITextView.js +16 -6
- package/compiledScripts/UITextView.js.map +2 -2
- package/compiledScripts/UIView.d.ts +7 -0
- package/compiledScripts/UIView.js +26 -0
- package/compiledScripts/UIView.js.map +2 -2
- package/compiledScripts/index.d.ts +1 -0
- package/compiledScripts/index.js +1 -0
- package/compiledScripts/index.js.map +2 -2
- package/package.json +1 -1
- package/scripts/UIActionIndicator.ts +8 -18
- package/scripts/UILoadingView.ts +201 -0
- package/scripts/UIRectangle.ts +16 -1
- package/scripts/UITableView.ts +124 -300
- package/scripts/UITextView.ts +23 -7
- package/scripts/UIView.ts +65 -14
- package/scripts/index.ts +2 -0
package/scripts/UITableView.ts
CHANGED
|
@@ -61,10 +61,7 @@ export class UITableView extends UINativeScrollView {
|
|
|
61
61
|
override animationDuration = 0.25
|
|
62
62
|
|
|
63
63
|
// Viewport scrolling properties
|
|
64
|
-
|
|
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
|
-
|
|
82
|
-
this._autoDetectScrollMode()
|
|
78
|
+
this._setupViewportScrollAndResizeHandlersIfNeeded()
|
|
83
79
|
|
|
84
80
|
}
|
|
85
81
|
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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.
|
|
147
|
-
this.
|
|
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
|
-
|
|
154
|
-
|
|
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(
|
|
166
|
-
window.addEventListener(
|
|
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.
|
|
112
|
+
if (entry.isIntersecting && this.isMemberOfViewTree) {
|
|
113
|
+
this._scheduleDrawVisibleRows()
|
|
174
114
|
}
|
|
175
115
|
})
|
|
176
116
|
},
|
|
177
117
|
{
|
|
178
118
|
root: null,
|
|
179
|
-
rootMargin:
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
//
|
|
475
|
-
if
|
|
476
|
-
|
|
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
|
-
//
|
|
480
|
-
|
|
481
|
-
|
|
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
|
|
322
|
+
for (let i = firstIndex; i <= lastIndex; i++) {
|
|
500
323
|
result.push(i)
|
|
501
324
|
}
|
|
502
325
|
return result
|
|
503
326
|
}
|
|
504
327
|
|
|
505
|
-
|
|
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
|
|
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
|
-
|
|
517
|
-
if (
|
|
343
|
+
// Check intersection
|
|
344
|
+
if (rowBottom >= firstVisibleY && rowTop <= lastVisibleY) {
|
|
518
345
|
result.push(i)
|
|
519
346
|
}
|
|
520
|
-
|
|
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) &&
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
762
|
-
|
|
763
|
-
|
|
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
|
-
|
|
822
|
-
|
|
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(
|
|
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
|
-
|
|
867
|
-
this._drawVisibleRowsInViewport()
|
|
868
|
-
} else {
|
|
869
|
-
this._drawVisibleRows()
|
|
870
|
-
}
|
|
694
|
+
this._drawVisibleRows()
|
|
871
695
|
|
|
872
696
|
this._needsDrawingOfVisibleRowsBeforeLayout = NO
|
|
873
697
|
|
package/scripts/UITextView.ts
CHANGED
|
@@ -35,10 +35,10 @@ export class UITextView extends UIView {
|
|
|
35
35
|
} as const
|
|
36
36
|
|
|
37
37
|
static textAlignment = {
|
|
38
|
-
"left": "
|
|
38
|
+
"left": "flex-start",
|
|
39
39
|
"center": "center",
|
|
40
|
-
"right": "
|
|
41
|
-
"justify": "
|
|
40
|
+
"right": "flex-end",
|
|
41
|
+
"justify": "stretch"
|
|
42
42
|
} as const
|
|
43
43
|
|
|
44
44
|
//#endregion
|
|
@@ -61,7 +61,24 @@ export class UITextView extends UIView {
|
|
|
61
61
|
|
|
62
62
|
this.textColor = this.textColor
|
|
63
63
|
|
|
64
|
-
this.userInteractionEnabled = YES
|
|
64
|
+
this.userInteractionEnabled = YES;
|
|
65
|
+
|
|
66
|
+
(this as UITextView).configureWithObject({
|
|
67
|
+
style: {
|
|
68
|
+
display: "flex",
|
|
69
|
+
flexDirection: "column", // Ensures vertical stacking logic
|
|
70
|
+
|
|
71
|
+
// 'safe' ensures that if content overflows, it aligns to the start (top)
|
|
72
|
+
// instead of overflowing upwards or downwards equally.
|
|
73
|
+
justifyContent: "safe center",
|
|
74
|
+
alignItems: "flex-start", // Keeps text left-aligned (change to "center" for horizontal center)
|
|
75
|
+
|
|
76
|
+
// Optional: ensure text wraps if it gets too long
|
|
77
|
+
whiteSpace: "normal",
|
|
78
|
+
wordWrap: "break-word",
|
|
79
|
+
overflowWrap: "break-word"
|
|
80
|
+
}
|
|
81
|
+
})
|
|
65
82
|
|
|
66
83
|
if (textViewType == UITextView.type.textArea) {
|
|
67
84
|
this.pausesPointerEvents = YES
|
|
@@ -188,12 +205,11 @@ export class UITextView extends UIView {
|
|
|
188
205
|
|
|
189
206
|
get textAlignment() {
|
|
190
207
|
// @ts-ignore
|
|
191
|
-
return this.style.
|
|
208
|
+
return this.style.alignItems
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
set textAlignment(textAlignment: ValueOf<typeof UITextView.textAlignment>) {
|
|
195
|
-
this.
|
|
196
|
-
this.style.textAlign = textAlignment
|
|
212
|
+
this.style.alignItems = textAlignment
|
|
197
213
|
}
|
|
198
214
|
|
|
199
215
|
//#endregion
|