@expo/ui 58.0.6 → 58.0.8
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/CHANGELOG.md +20 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +9 -0
- package/android/src/main/java/expo/modules/ui/LazyColumnView.kt +6 -1
- package/android/src/main/java/expo/modules/ui/LazyItemsView.kt +313 -0
- package/android/src/main/java/expo/modules/ui/LazyRowView.kt +6 -1
- package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +11 -3
- package/android/src/main/java/expo/modules/ui/RNHostView.kt +18 -4
- package/android/src/main/java/expo/modules/ui/SemanticsModifier.kt +2 -1
- package/build/jetpack-compose/LazyColumn/index.d.ts +6 -0
- package/build/jetpack-compose/LazyColumn/index.js +2 -0
- package/build/jetpack-compose/LazyColumn/index.js.map +1 -1
- package/build/jetpack-compose/LazyItems/index.d.ts +54 -0
- package/build/jetpack-compose/LazyItems/index.js +63 -0
- package/build/jetpack-compose/LazyItems/index.js.map +1 -0
- package/build/jetpack-compose/LazyRow/index.d.ts +6 -0
- package/build/jetpack-compose/LazyRow/index.js +2 -0
- package/build/jetpack-compose/LazyRow/index.js.map +1 -1
- package/build/jetpack-compose/index.d.ts +1 -0
- package/build/jetpack-compose/index.js.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +15 -3
- package/build/jetpack-compose/modifiers/index.js.map +1 -1
- package/build/recycling/useRecycledRows.d.ts +52 -0
- package/build/recycling/useRecycledRows.js +121 -0
- package/build/recycling/useRecycledRows.js.map +1 -0
- package/build/recycling/window.js.map +1 -0
- package/build/swift-ui/List/DataListForEach.d.ts +2 -9
- package/build/swift-ui/List/DataListForEach.js +15 -106
- package/build/swift-ui/List/DataListForEach.js.map +1 -1
- package/build/swift-ui/List/ListForEach.js +3 -2
- package/build/swift-ui/List/ListForEach.js.map +1 -1
- package/build/swift-ui/modifiers/index.d.ts +5 -1
- package/build/swift-ui/modifiers/index.js.map +1 -1
- package/build/swift-ui/modifiers/presentationModifiers.d.ts +8 -0
- package/build/swift-ui/modifiers/presentationModifiers.js +9 -0
- package/build/swift-ui/modifiers/presentationModifiers.js.map +1 -1
- package/build/universal/State.android.d.ts +1 -3
- package/build/universal/State.d.ts +2 -3
- package/build/universal/State.ios.d.ts +1 -3
- package/build/universal/State.js +10 -4
- package/build/universal/State.js.map +1 -1
- package/build/universal/transformStyle.ios.js +4 -3
- package/build/universal/transformStyle.ios.js.map +1 -1
- package/build/universal/types.d.ts +24 -0
- package/build/universal/types.js +8 -2
- package/build/universal/types.js.map +1 -1
- package/expo-module.config.json +1 -1
- package/ios/Modifiers/PresentationModifiers.swift +10 -0
- package/ios/Modifiers/ViewModifierRegistry.swift +4 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.6/expo.modules.ui-58.0.6-sources.jar → 58.0.8/expo.modules.ui-58.0.8-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.6/expo.modules.ui-58.0.6.module → 58.0.8/expo.modules.ui-58.0.8.module} +24 -24
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.6/expo.modules.ui-58.0.6.pom → 58.0.8/expo.modules.ui-58.0.8.pom} +3 -3
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.8/expo.modules.ui-58.0.8.pom.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
- package/package.json +4 -4
- package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
- package/src/jetpack-compose/LazyColumn/index.tsx +3 -0
- package/src/jetpack-compose/LazyItems/index.tsx +121 -0
- package/src/jetpack-compose/LazyRow/index.tsx +3 -0
- package/src/jetpack-compose/index.ts +1 -0
- package/src/jetpack-compose/modifiers/index.ts +16 -1
- package/src/recycling/useRecycledRows.tsx +200 -0
- package/src/swift-ui/List/DataListForEach.tsx +21 -142
- package/src/swift-ui/List/ListForEach.tsx +3 -2
- package/src/swift-ui/modifiers/index.ts +5 -1
- package/src/swift-ui/modifiers/presentationModifiers.ts +10 -0
- package/src/universal/State.android.ts +1 -1
- package/src/universal/State.ios.ts +1 -1
- package/src/universal/State.ts +12 -4
- package/src/universal/transformStyle.ios.ts +5 -2
- package/src/universal/types.ts +27 -0
- package/build/swift-ui/List/window.js.map +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.6/expo.modules.ui-58.0.6.pom.sha512 +0 -1
- /package/build/{swift-ui/List → recycling}/window.d.ts +0 -0
- /package/build/{swift-ui/List → recycling}/window.js +0 -0
- /package/src/{swift-ui/List → recycling}/window.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,24 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 58.0.8 — 2026-09-28
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- [iOS] Export the `FrameAlignment` type for the `alignment` parameter of `frame()`. ([#50702](https://github.com/expo/expo/pull/50702) by [@amandeepmittal](https://github.com/amandeepmittal))
|
|
18
|
+
- [Android] Add `contentDescription` to the `semantics` modifier, so TalkBack can announce a label other than the visible content. ([#50688](https://github.com/expo/expo/pull/50688) by [@enavermate](https://github.com/enavermate))
|
|
19
|
+
- Added `get()` and `set()` to the universal `ObservableState` type and to the web implementation of `useNativeState`, as React Compiler-compliant alternatives to `.value`. ([#50684](https://github.com/expo/expo/pull/50684) by [@Den1Marshall](https://github.com/Den1Marshall))
|
|
20
|
+
|
|
21
|
+
## 58.0.7 — 2026-09-25
|
|
22
|
+
|
|
23
|
+
### 🎉 New features
|
|
24
|
+
|
|
25
|
+
- [iOS] Added `presentationCornerRadius` modifier. ([#50632](https://github.com/expo/expo/pull/50632) by [@shanelord01](https://github.com/shanelord01))
|
|
26
|
+
|
|
27
|
+
### 🐛 Bug fixes
|
|
28
|
+
|
|
29
|
+
- [iOS] Fixed `onPress` on universal components such as `Row` and `Column` not firing when tapping empty space, such as a `Spacer`. ([#50599](https://github.com/expo/expo/pull/50599) by [@expo-bot](https://github.com/expo-bot))
|
|
30
|
+
|
|
13
31
|
## 58.0.6 — 2026-09-23
|
|
14
32
|
|
|
15
33
|
### 🛠 Breaking changes
|
|
@@ -19,6 +37,7 @@
|
|
|
19
37
|
### 🎉 New features
|
|
20
38
|
|
|
21
39
|
- [iOS] `List.ForEach` recycles rows from a small pool around the visible range, so large lists only render the rows near the viewport. Deprecated element children in favor of this form. ([#49975](https://github.com/expo/expo/pull/49975) by [@nishan](https://github.com/intergalacticspacehighway))
|
|
40
|
+
- [Android] Added `LazyColumn.Items` and `LazyRow.Items`, which render rows from `data` and `keyExtractor` with a `children` function: `{({ item, index }) => <Row item={item} />}`. Rows are recycled from a small pool around the visible range, so large lists only render the rows near the viewport. Set `recycling={false}` to render every row. ([#50258](https://github.com/expo/expo/pull/50258) by [@nishan](https://github.com/intergalacticspacehighway))
|
|
22
41
|
|
|
23
42
|
## 58.0.5 — 2026-09-22
|
|
24
43
|
|
|
@@ -101,6 +120,7 @@
|
|
|
101
120
|
|
|
102
121
|
### 🐛 Bug fixes
|
|
103
122
|
|
|
123
|
+
- [Android] Fix hosted React Native content sliding off the top of a `BottomSheet` when the keyboard opens. ([#49399](https://github.com/expo/expo/issues/49399) by [@starsky-nev](https://github.com/starsky-nev)) ([#49427](https://github.com/expo/expo/pull/49427) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
104
124
|
- [Android] Fix `DatePickerDialog` preselecting today when `initialDate` is omitted, and keep its confirm button disabled while no date is selected so `onDateSelected` never receives an invalid date. ([#49898](https://github.com/expo/expo/pull/49898) by [@pataar](https://github.com/pataar))
|
|
105
125
|
- [Android][iOS] Fix `community/bottom-sheet` content shrinking to its own width instead of filling the sheet when the sheet sizes to its content. ([#49742](https://github.com/expo/expo/issues/49742) by [@agung-adhinata](https://github.com/agung-adhinata)) ([#49762](https://github.com/expo/expo/pull/49762) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
106
126
|
- [Android] Fixed a `Text` or an `Icon` with no explicit color rendering black inside `Host`, which made it unreadable in the dark color scheme. `Host` now provides `LocalContentColor` from the color scheme. ([#49697](https://github.com/expo/expo/pull/49697) by [@expo-bot](https://github.com/expo-bot))
|
package/android/build.gradle
CHANGED
|
@@ -12,13 +12,13 @@ apply plugin: 'expo-module-gradle-plugin'
|
|
|
12
12
|
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
|
13
13
|
|
|
14
14
|
group = 'expo.modules.ui'
|
|
15
|
-
version = '58.0.
|
|
15
|
+
version = '58.0.8'
|
|
16
16
|
|
|
17
17
|
android {
|
|
18
18
|
namespace "expo.modules.ui"
|
|
19
19
|
defaultConfig {
|
|
20
20
|
versionCode 1
|
|
21
|
-
versionName "58.0.
|
|
21
|
+
versionName "58.0.8"
|
|
22
22
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
23
23
|
}
|
|
24
24
|
buildFeatures {
|
|
@@ -203,6 +203,15 @@ class ExpoUIModule : Module() {
|
|
|
203
203
|
}
|
|
204
204
|
View(LazyColumnView::class)
|
|
205
205
|
View(LazyRowView::class)
|
|
206
|
+
View(LazyItemsView::class) {
|
|
207
|
+
Events("onWindowChange")
|
|
208
|
+
|
|
209
|
+
OnViewDestroys { view: LazyItemsView ->
|
|
210
|
+
view.cancelPendingWindowChange()
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
View(LazyItemsPoolView::class)
|
|
214
|
+
View(LazyItemsSlotView::class)
|
|
206
215
|
|
|
207
216
|
// Class-based views so TooltipBoxView can detect them by type via findChildOfType
|
|
208
217
|
View(PlainTooltipView::class)
|
|
@@ -69,7 +69,8 @@ class LazyColumnView(context: Context, appContext: AppContext) :
|
|
|
69
69
|
val padding = props.contentPadding.value
|
|
70
70
|
|
|
71
71
|
LazyColumn(
|
|
72
|
-
modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
|
|
72
|
+
modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
|
|
73
|
+
.lazyRecycledItemsCrossAxis(this@LazyColumnView, isVertical = true),
|
|
73
74
|
verticalArrangement = verticalArrangement,
|
|
74
75
|
horizontalAlignment = horizontalAlignment,
|
|
75
76
|
contentPadding = PaddingValues(
|
|
@@ -82,6 +83,10 @@ class LazyColumnView(context: Context, appContext: AppContext) :
|
|
|
82
83
|
val count = composableChildCount.intValue
|
|
83
84
|
for (index in 0..<count) {
|
|
84
85
|
val child = getChildAt(index) as? ExpoComposeView<*> ?: continue
|
|
86
|
+
if (child is LazyItemsView) {
|
|
87
|
+
lazyRecycledItems(child, this@Content, isVertical = true)
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
85
90
|
item {
|
|
86
91
|
with(this@Content) {
|
|
87
92
|
with(child) {
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
package expo.modules.ui
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.os.Handler
|
|
6
|
+
import android.os.Looper
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import androidx.compose.foundation.layout.Box
|
|
10
|
+
import androidx.compose.foundation.layout.Spacer
|
|
11
|
+
import androidx.compose.foundation.layout.fillMaxHeight
|
|
12
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
13
|
+
import androidx.compose.foundation.layout.height
|
|
14
|
+
import androidx.compose.foundation.layout.width
|
|
15
|
+
import androidx.compose.foundation.lazy.LazyListScope
|
|
16
|
+
import androidx.compose.runtime.Composable
|
|
17
|
+
import androidx.compose.runtime.DisposableEffect
|
|
18
|
+
import androidx.compose.runtime.MutableIntState
|
|
19
|
+
import androidx.compose.runtime.MutableState
|
|
20
|
+
import androidx.compose.runtime.mutableIntStateOf
|
|
21
|
+
import androidx.compose.runtime.mutableStateOf
|
|
22
|
+
import androidx.compose.runtime.remember
|
|
23
|
+
import androidx.compose.ui.Modifier
|
|
24
|
+
import androidx.compose.ui.layout.layout
|
|
25
|
+
import androidx.compose.ui.layout.onSizeChanged
|
|
26
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
27
|
+
import androidx.compose.ui.unit.dp
|
|
28
|
+
import expo.modules.kotlin.AppContext
|
|
29
|
+
import expo.modules.kotlin.records.Field
|
|
30
|
+
import expo.modules.kotlin.records.Record
|
|
31
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
32
|
+
import expo.modules.kotlin.views.ComposableScope
|
|
33
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
34
|
+
import expo.modules.kotlin.views.ExpoComposeView
|
|
35
|
+
import expo.modules.kotlin.views.OptimizedComposeProps
|
|
36
|
+
|
|
37
|
+
@OptimizedComposeProps
|
|
38
|
+
data class LazyItemsProps(
|
|
39
|
+
val itemKeys: MutableState<List<String>> = mutableStateOf(emptyList()),
|
|
40
|
+
val revision: MutableState<Int> = mutableStateOf(0),
|
|
41
|
+
val estimatedItemSize: MutableState<Double> = mutableStateOf(64.0)
|
|
42
|
+
) : ComposeProps
|
|
43
|
+
|
|
44
|
+
internal data class WindowChangeEvent(
|
|
45
|
+
@Field val first: Int,
|
|
46
|
+
@Field val last: Int,
|
|
47
|
+
@Field val revision: Int
|
|
48
|
+
) : Record
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A block of recycled items inside [LazyColumnView] or [LazyRowView]. It renders no content of its
|
|
52
|
+
* own: [lazyRecycledItems] expands it into one lazy item per key, each backed by a slot of its
|
|
53
|
+
* pool child.
|
|
54
|
+
*/
|
|
55
|
+
@SuppressLint("ViewConstructor")
|
|
56
|
+
class LazyItemsView(context: Context, appContext: AppContext) :
|
|
57
|
+
ExpoComposeView<LazyItemsProps>(context, appContext) {
|
|
58
|
+
override val props = LazyItemsProps()
|
|
59
|
+
private val onWindowChange by EventDispatcher<WindowChangeEvent>()
|
|
60
|
+
|
|
61
|
+
internal val pool: MutableState<LazyItemsPoolView?> = mutableStateOf(null)
|
|
62
|
+
internal val window = LazyItemsWindow { first, last, revision ->
|
|
63
|
+
onWindowChange(WindowChangeEvent(first, last, revision))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override fun onViewAdded(child: View?) {
|
|
67
|
+
super.onViewAdded(child)
|
|
68
|
+
pool.value = findChildOfType<LazyItemsPoolView>(this)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun onViewRemoved(child: View?) {
|
|
72
|
+
super.onViewRemoved(child)
|
|
73
|
+
pool.value = findChildOfType<LazyItemsPoolView>(this)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
internal fun cancelPendingWindowChange() {
|
|
77
|
+
window.cancel()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Composable
|
|
81
|
+
override fun ComposableScope.Content() = Unit
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@OptimizedComposeProps
|
|
85
|
+
class LazyItemsPoolProps : ComposeProps
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Holds the recycled slots, so mounting a slot never republishes the props of [LazyItemsView].
|
|
89
|
+
*/
|
|
90
|
+
@SuppressLint("ViewConstructor")
|
|
91
|
+
class LazyItemsPoolView(context: Context, appContext: AppContext) :
|
|
92
|
+
ExpoComposeView<LazyItemsPoolProps>(context, appContext) {
|
|
93
|
+
override val props = LazyItemsPoolProps()
|
|
94
|
+
|
|
95
|
+
internal val slotCount: MutableIntState = mutableIntStateOf(0)
|
|
96
|
+
|
|
97
|
+
override fun onViewAdded(child: View?) {
|
|
98
|
+
super.onViewAdded(child)
|
|
99
|
+
slotCount.intValue = childCount
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
override fun onViewRemoved(child: View?) {
|
|
103
|
+
super.onViewRemoved(child)
|
|
104
|
+
slotCount.intValue = childCount
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@Composable
|
|
108
|
+
override fun ComposableScope.Content() = Unit
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@OptimizedComposeProps
|
|
112
|
+
data class LazyItemsSlotProps(
|
|
113
|
+
val itemKey: MutableState<String> = mutableStateOf(""),
|
|
114
|
+
val index: MutableState<Int> = mutableStateOf(0),
|
|
115
|
+
val revision: MutableState<Int> = mutableStateOf(0)
|
|
116
|
+
) : ComposeProps
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* One recycled slot. JS assigns item `index` to slot `index % slotCount` and republishes these
|
|
120
|
+
* props when the slot moves to another item.
|
|
121
|
+
*/
|
|
122
|
+
@SuppressLint("ViewConstructor")
|
|
123
|
+
class LazyItemsSlotView(context: Context, appContext: AppContext) :
|
|
124
|
+
ExpoComposeView<LazyItemsSlotProps>(context, appContext) {
|
|
125
|
+
override val props = LazyItemsSlotProps()
|
|
126
|
+
|
|
127
|
+
@Composable
|
|
128
|
+
override fun ComposableScope.Content() {
|
|
129
|
+
Children(this)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Expands a [LazyItemsView] child into one lazy item per key. An item composes its slot only while
|
|
135
|
+
* the slot still carries that item, and shows a placeholder of the measured or estimated size
|
|
136
|
+
* while JS moves the slot over.
|
|
137
|
+
*/
|
|
138
|
+
internal fun LazyListScope.lazyRecycledItems(
|
|
139
|
+
view: LazyItemsView,
|
|
140
|
+
scope: ComposableScope,
|
|
141
|
+
isVertical: Boolean
|
|
142
|
+
) {
|
|
143
|
+
val keys = view.props.itemKeys.value
|
|
144
|
+
val revision = view.props.revision.value
|
|
145
|
+
val estimatedItemSize = view.props.estimatedItemSize.value
|
|
146
|
+
if (keys.isEmpty()) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
val window = view.window
|
|
150
|
+
items(count = keys.size, key = { keys[it] }) { index ->
|
|
151
|
+
val itemKey = keys[index]
|
|
152
|
+
val token = remember(itemKey, index, revision) { Any() }
|
|
153
|
+
DisposableEffect(token) {
|
|
154
|
+
window.appear(itemKey, index, token, revision, keys)
|
|
155
|
+
onDispose { window.disappear(itemKey, token) }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
val pool = view.pool.value
|
|
159
|
+
val slotCount = pool?.slotCount?.intValue ?: 0
|
|
160
|
+
val slot = if (pool != null && slotCount > 0) {
|
|
161
|
+
pool.getChildAt(index % slotCount) as? LazyItemsSlotView
|
|
162
|
+
} else {
|
|
163
|
+
null
|
|
164
|
+
}
|
|
165
|
+
// A slot carries this item only until JS moves it to another one.
|
|
166
|
+
val content = slot?.takeIf {
|
|
167
|
+
it.props.itemKey.value == itemKey &&
|
|
168
|
+
it.props.index.value == index &&
|
|
169
|
+
it.props.revision.value == revision
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
val density = LocalDensity.current
|
|
173
|
+
val placeholderSize = with(density) {
|
|
174
|
+
window.size(itemKey, estimatedItemSize.dp.roundToPx()).toDp()
|
|
175
|
+
}
|
|
176
|
+
Box(
|
|
177
|
+
modifier = Modifier.onSizeChanged { size ->
|
|
178
|
+
if (content != null) {
|
|
179
|
+
window.measure(itemKey, if (isVertical) size.height else size.width, revision)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
) {
|
|
183
|
+
if (content != null) {
|
|
184
|
+
with(scope) {
|
|
185
|
+
with(content) {
|
|
186
|
+
Content()
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
Spacer(
|
|
191
|
+
modifier = if (isVertical) {
|
|
192
|
+
Modifier.fillMaxWidth().height(placeholderSize)
|
|
193
|
+
} else {
|
|
194
|
+
Modifier.fillMaxHeight().width(placeholderSize)
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Clears the cached item sizes of every [LazyItemsView] child when the list's cross-axis
|
|
204
|
+
* constraint changes. It runs before the items measure, so it never discards fresh sizes.
|
|
205
|
+
*/
|
|
206
|
+
internal fun Modifier.lazyRecycledItemsCrossAxis(list: ViewGroup, isVertical: Boolean): Modifier =
|
|
207
|
+
layout { measurable, constraints ->
|
|
208
|
+
val crossAxisSize = if (isVertical) constraints.maxWidth else constraints.maxHeight
|
|
209
|
+
for (index in 0..<list.childCount) {
|
|
210
|
+
(list.getChildAt(index) as? LazyItemsView)?.window?.updateCrossAxisSize(crossAxisSize)
|
|
211
|
+
}
|
|
212
|
+
val placeable = measurable.measure(constraints)
|
|
213
|
+
layout(placeable.width, placeable.height) {
|
|
214
|
+
placeable.place(0, 0)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Tracks the live items without triggering recomposition, and batches window requests to JS.
|
|
220
|
+
*/
|
|
221
|
+
internal class LazyItemsWindow(
|
|
222
|
+
private val send: (first: Int, last: Int, revision: Int) -> Unit
|
|
223
|
+
) {
|
|
224
|
+
private val handler = Handler(Looper.getMainLooper())
|
|
225
|
+
private val appeared = mutableMapOf<String, Int>()
|
|
226
|
+
private val tokens = mutableMapOf<String, Any>()
|
|
227
|
+
private val sizes = mutableMapOf<String, Int>()
|
|
228
|
+
private var crossAxisSize = 0
|
|
229
|
+
private var revision = -1
|
|
230
|
+
private var pending = false
|
|
231
|
+
private var lastSent: Triple<Int, Int, Int>? = null
|
|
232
|
+
|
|
233
|
+
fun appear(key: String, index: Int, token: Any, revision: Int, keys: List<String>) {
|
|
234
|
+
reset(revision, keys)
|
|
235
|
+
if (index !in keys.indices || keys[index] != key) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
appeared[key] = index
|
|
239
|
+
tokens[key] = token
|
|
240
|
+
schedule()
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
fun disappear(key: String, token: Any) {
|
|
244
|
+
// Ignore callbacks from an item that has been replaced.
|
|
245
|
+
if (tokens[key] !== token) {
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
appeared.remove(key)
|
|
249
|
+
tokens.remove(key)
|
|
250
|
+
if (appeared.isEmpty()) {
|
|
251
|
+
lastSent = null
|
|
252
|
+
}
|
|
253
|
+
schedule()
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fun size(key: String, fallback: Int): Int = sizes[key] ?: fallback
|
|
257
|
+
|
|
258
|
+
fun measure(key: String, size: Int, revision: Int) {
|
|
259
|
+
if (revision != this.revision || size <= 0) {
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
sizes[key] = size
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fun updateCrossAxisSize(size: Int) {
|
|
266
|
+
if (size == crossAxisSize) {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
if (crossAxisSize > 0) {
|
|
270
|
+
sizes.clear()
|
|
271
|
+
}
|
|
272
|
+
crossAxisSize = size
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fun cancel() {
|
|
276
|
+
handler.removeCallbacksAndMessages(null)
|
|
277
|
+
pending = false
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private fun reset(newRevision: Int, keys: List<String>) {
|
|
281
|
+
if (revision == newRevision) {
|
|
282
|
+
return
|
|
283
|
+
}
|
|
284
|
+
revision = newRevision
|
|
285
|
+
sizes.clear()
|
|
286
|
+
val positions = HashMap<String, Int>(keys.size)
|
|
287
|
+
keys.forEachIndexed { index, key -> positions[key] = index }
|
|
288
|
+
val kept = appeared.keys.mapNotNull { key -> positions[key]?.let { key to it } }
|
|
289
|
+
appeared.clear()
|
|
290
|
+
appeared.putAll(kept)
|
|
291
|
+
tokens.keys.retainAll { positions.containsKey(it) }
|
|
292
|
+
lastSent = null
|
|
293
|
+
schedule()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private fun schedule() {
|
|
297
|
+
if (pending) {
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
pending = true
|
|
301
|
+
handler.post {
|
|
302
|
+
pending = false
|
|
303
|
+
val first = appeared.values.minOrNull() ?: return@post
|
|
304
|
+
val last = appeared.values.maxOrNull() ?: return@post
|
|
305
|
+
val event = Triple(first, last, revision)
|
|
306
|
+
if (event == lastSent) {
|
|
307
|
+
return@post
|
|
308
|
+
}
|
|
309
|
+
lastSent = event
|
|
310
|
+
send(first, last, revision)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -58,7 +58,8 @@ class LazyRowView(context: Context, appContext: AppContext) :
|
|
|
58
58
|
val padding = props.contentPadding.value
|
|
59
59
|
|
|
60
60
|
LazyRow(
|
|
61
|
-
modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
|
|
61
|
+
modifier = ModifierRegistry.applyModifiers(props.modifiers.value, appContext, this@Content, globalEventDispatcher)
|
|
62
|
+
.lazyRecycledItemsCrossAxis(this@LazyRowView, isVertical = false),
|
|
62
63
|
horizontalArrangement = horizontalArrangement,
|
|
63
64
|
verticalAlignment = verticalAlignment,
|
|
64
65
|
contentPadding = PaddingValues(
|
|
@@ -71,6 +72,10 @@ class LazyRowView(context: Context, appContext: AppContext) :
|
|
|
71
72
|
val count = composableChildCount.intValue
|
|
72
73
|
for (index in 0..<count) {
|
|
73
74
|
val child = getChildAt(index) as? ExpoComposeView<*> ?: continue
|
|
75
|
+
if (child is LazyItemsView) {
|
|
76
|
+
lazyRecycledItems(child, this@Content, isVertical = false)
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
74
79
|
item {
|
|
75
80
|
with(this@Content) {
|
|
76
81
|
with(child) {
|
|
@@ -67,6 +67,7 @@ import androidx.compose.ui.layout.onVisibilityChanged
|
|
|
67
67
|
import androidx.compose.ui.layout.positionInWindow
|
|
68
68
|
import androidx.compose.ui.platform.LocalDensity
|
|
69
69
|
import androidx.compose.ui.semantics.Role
|
|
70
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
70
71
|
import androidx.compose.ui.semantics.contentType
|
|
71
72
|
import androidx.compose.ui.semantics.semantics
|
|
72
73
|
import androidx.compose.ui.unit.DpOffset
|
|
@@ -681,9 +682,16 @@ object ModifierRegistry {
|
|
|
681
682
|
|
|
682
683
|
register("semantics") { map, _, appContext, _ ->
|
|
683
684
|
val params = recordFromMap<SemanticsParams>(map, appContext)
|
|
684
|
-
params.contentType.toContentType()
|
|
685
|
-
|
|
686
|
-
|
|
685
|
+
val type = params.contentType.toContentType()
|
|
686
|
+
val description = params.contentDescription
|
|
687
|
+
if (type == null && description == null) {
|
|
688
|
+
Modifier
|
|
689
|
+
} else {
|
|
690
|
+
Modifier.semantics {
|
|
691
|
+
type?.let { contentType = it }
|
|
692
|
+
description?.let { contentDescription = it }
|
|
693
|
+
}
|
|
694
|
+
}
|
|
687
695
|
}
|
|
688
696
|
|
|
689
697
|
register("clip") { map, _, appContext, _ ->
|
|
@@ -10,9 +10,11 @@ import android.view.ViewParent
|
|
|
10
10
|
import android.widget.FrameLayout
|
|
11
11
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
12
12
|
import androidx.compose.foundation.layout.requiredSize
|
|
13
|
+
import androidx.compose.foundation.layout.wrapContentSize
|
|
13
14
|
import androidx.compose.runtime.Composable
|
|
14
15
|
import androidx.compose.runtime.MutableState
|
|
15
16
|
import androidx.compose.runtime.mutableStateOf
|
|
17
|
+
import androidx.compose.ui.Alignment
|
|
16
18
|
import androidx.compose.ui.Modifier
|
|
17
19
|
import androidx.compose.ui.layout.onGloballyPositioned
|
|
18
20
|
import androidx.compose.ui.layout.onSizeChanged
|
|
@@ -180,10 +182,22 @@ internal class RNHostView(context: Context, appContext: AppContext) :
|
|
|
180
182
|
|
|
181
183
|
return with(density) {
|
|
182
184
|
if (childSize.width > 0 && childSize.height > 0) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
// When RNHostView's size is greater than its parent, then parent centers RNHostView and truncates its top and bottom.
|
|
186
|
+
// e.g. Parent size = 200px, RNHostView size = 300px, the parent will position the RNHostView at center and truncate 50px from top and bottom.
|
|
187
|
+
// This causes issues where the top of RNHostView can go out of screen.
|
|
188
|
+
// These scenario mostly happen when a Keyboard opens in a sheet.
|
|
189
|
+
// https://github.com/expo/expo/issues/49399
|
|
190
|
+
// Adding wrapContentSize with Alignment.TopCenter and unbounded = true
|
|
191
|
+
// makes sure that the RNHostView is always positioned at the top of its parent.
|
|
192
|
+
// Only the vertical axis changes. A matchContents child is measured unconstrained, so it is
|
|
193
|
+
// routinely wider than its Compose slot, and centering it horizontally is what keeps its
|
|
194
|
+
// contents lined up with the parent.
|
|
195
|
+
Modifier
|
|
196
|
+
.wrapContentSize(Alignment.TopCenter, unbounded = true)
|
|
197
|
+
.requiredSize(
|
|
198
|
+
childSize.width.toDp(),
|
|
199
|
+
childSize.height.toDp()
|
|
200
|
+
)
|
|
187
201
|
} else {
|
|
188
202
|
Modifier
|
|
189
203
|
}
|
|
@@ -7,7 +7,8 @@ import expo.modules.kotlin.types.OptimizedRecord
|
|
|
7
7
|
|
|
8
8
|
@OptimizedRecord
|
|
9
9
|
internal data class SemanticsParams(
|
|
10
|
-
@Field val contentType: String? = null
|
|
10
|
+
@Field val contentType: String? = null,
|
|
11
|
+
@Field val contentDescription: String? = null
|
|
11
12
|
) : Record
|
|
12
13
|
|
|
13
14
|
internal fun String?.toContentType(): ContentType? = when (this) {
|
|
@@ -49,3 +49,9 @@ export interface LazyColumnProps {
|
|
|
49
49
|
* A lazy column component that efficiently displays a vertically scrolling list.
|
|
50
50
|
*/
|
|
51
51
|
export declare function LazyColumn(props: LazyColumnProps): import("react").JSX.Element;
|
|
52
|
+
export declare namespace LazyColumn {
|
|
53
|
+
var Items: {
|
|
54
|
+
<ItemT>({ recycling, ...props }: import("..").LazyItemsProps<ItemT>): import("react").JSX.Element;
|
|
55
|
+
displayName: string;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { requireNativeView } from 'expo';
|
|
3
|
+
import { LazyItems } from '../LazyItems';
|
|
3
4
|
import { createViewModifierEventListener } from '../modifiers/utils';
|
|
4
5
|
const LazyColumnNativeView = requireNativeView('ExpoUI', 'LazyColumnView');
|
|
5
6
|
function transformProps(props) {
|
|
@@ -17,5 +18,6 @@ function transformProps(props) {
|
|
|
17
18
|
...transformProps(props)
|
|
18
19
|
});
|
|
19
20
|
}
|
|
21
|
+
LazyColumn.Items = LazyItems;
|
|
20
22
|
|
|
21
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["jetpack-compose/LazyColumn/index.tsx"],"sourcesContent":[null],"names":["requireNativeView","createViewModifierEventListener","LazyColumnNativeView","transformProps","props","modifiers","restProps","undefined","LazyColumn"],"mappings":";AAAA,SAASA,iBAAiB,QAAQ,OAAO;AAGzC,SAASC,+BAA+B,QAAQ,qBAAqB;AAwDrE,MAAMC,
|
|
1
|
+
{"version":3,"sources":["jetpack-compose/LazyColumn/index.tsx"],"sourcesContent":[null],"names":["requireNativeView","LazyItems","createViewModifierEventListener","LazyColumnNativeView","transformProps","props","modifiers","restProps","undefined","LazyColumn","Items"],"mappings":";AAAA,SAASA,iBAAiB,QAAQ,OAAO;AAGzC,SAASC,SAAS,QAAQ,eAAe;AACzC,SAASC,+BAA+B,QAAQ,qBAAqB;AAwDrE,MAAMC,uBAAmEH,kBACvE,UACA;AAGF,SAASI,eAAeC,KAAsB;IAC5C,MAAM,EAAEC,SAAS,EAAE,GAAGC,WAAW,GAAGF;IACpC,OAAO;QACLC;QACA,GAAIA,YAAYJ,gCAAgCI,aAAaE,SAAS;QACtE,GAAGD,SAAS;IACd;AACF;AAEA;;CAEC,GACD,OAAO,SAASE,WAAWJ,KAAsB;IAC/C,qBAAO,KAACF;QAAsB,GAAGC,eAAeC,MAAM;;AACxD;AAEAI,WAAWC,KAAK,GAAGT"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type RenderItem } from '../../recycling/useRecycledRows';
|
|
2
|
+
export interface LazyItemsProps<ItemT> {
|
|
3
|
+
/** Items to display. Replace the array when updating data. */
|
|
4
|
+
data: readonly ItemT[];
|
|
5
|
+
/** Returns a stable, unique string key, also used as the lazy list item key. */
|
|
6
|
+
keyExtractor: (item: ItemT, index: number) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Renders a row. Wrap it in `useCallback`, or every row re-renders on each parent render.
|
|
9
|
+
* Recycled rows are reused for other items, so their local state (`useState`) carries over.
|
|
10
|
+
* Reset it when the item changes, or keep the state outside the row.
|
|
11
|
+
*/
|
|
12
|
+
children: RenderItem<ItemT>;
|
|
13
|
+
/**
|
|
14
|
+
* Renders only the rows near the visible range and reuses them while scrolling. Set to `false` to
|
|
15
|
+
* render every row at once. Set it once; changing it remounts the rows.
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
recycling?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Extra rows to prepare on each side of the visible rows. Must be a non-negative integer.
|
|
21
|
+
* Ignored when `recycling` is `false`.
|
|
22
|
+
* @default 10
|
|
23
|
+
*/
|
|
24
|
+
overscanCount?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Placeholder size in dp along the scroll axis, until a row is measured. Must be positive.
|
|
27
|
+
* Measurements reset when the data changes. In `LazyColumn.Items` they also reset when the list
|
|
28
|
+
* width changes. Ignored when `recycling` is `false`.
|
|
29
|
+
* @default 64
|
|
30
|
+
*/
|
|
31
|
+
estimatedItemSize?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A block of recycled rows inside `LazyColumn` or `LazyRow`, mirroring the Compose
|
|
35
|
+
* `items(count, key)` builder. Only a small pool of rows around the visible range is mounted,
|
|
36
|
+
* so large data sets stay cheap. Rows that are not ready yet show a placeholder of
|
|
37
|
+
* `estimatedItemSize`, or of the size last measured for that item.
|
|
38
|
+
*
|
|
39
|
+
* Mount it as a direct child of `LazyColumn` or `LazyRow`. Plain children of the same list stay
|
|
40
|
+
* single items, so static and recycled content can be mixed in order.
|
|
41
|
+
* @platform android
|
|
42
|
+
*/
|
|
43
|
+
export declare const LazyItems: {
|
|
44
|
+
<ItemT>({ recycling, ...props }: LazyItemsProps<ItemT>): import("react").JSX.Element;
|
|
45
|
+
displayName: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* @hidden
|
|
49
|
+
* Creates the `Items` component of one lazy list, so its errors name that list.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createLazyItems(componentName: string): {
|
|
52
|
+
<ItemT>({ recycling, ...props }: LazyItemsProps<ItemT>): import("react").JSX.Element;
|
|
53
|
+
displayName: string;
|
|
54
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { requireNativeView } from 'expo';
|
|
3
|
+
import { Fragment } from 'react';
|
|
4
|
+
import { useItemKeys, useRecycledRows } from '../../recycling/useRecycledRows';
|
|
5
|
+
const LazyItemsNativeView = requireNativeView('ExpoUI', 'LazyItemsView');
|
|
6
|
+
const LazyItemsSlotNativeView = requireNativeView('ExpoUI', 'LazyItemsSlotView');
|
|
7
|
+
const LazyItemsPoolNativeView = requireNativeView('ExpoUI', 'LazyItemsPoolView');
|
|
8
|
+
/**
|
|
9
|
+
* A block of recycled rows inside `LazyColumn` or `LazyRow`, mirroring the Compose
|
|
10
|
+
* `items(count, key)` builder. Only a small pool of rows around the visible range is mounted,
|
|
11
|
+
* so large data sets stay cheap. Rows that are not ready yet show a placeholder of
|
|
12
|
+
* `estimatedItemSize`, or of the size last measured for that item.
|
|
13
|
+
*
|
|
14
|
+
* Mount it as a direct child of `LazyColumn` or `LazyRow`. Plain children of the same list stay
|
|
15
|
+
* single items, so static and recycled content can be mixed in order.
|
|
16
|
+
* @platform android
|
|
17
|
+
*/ export const LazyItems = createLazyItems('LazyColumn.Items');
|
|
18
|
+
/**
|
|
19
|
+
* @hidden
|
|
20
|
+
* Creates the `Items` component of one lazy list, so its errors name that list.
|
|
21
|
+
*/ export function createLazyItems(componentName) {
|
|
22
|
+
function Items({ recycling = true, ...props }) {
|
|
23
|
+
return recycling ? /*#__PURE__*/ _jsx(RecycledItems, {
|
|
24
|
+
...props
|
|
25
|
+
}) : /*#__PURE__*/ _jsx(StaticItems, {
|
|
26
|
+
...props
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
// Each row is a plain child of the lazy list, so it becomes one lazy item.
|
|
30
|
+
function StaticItems({ data, keyExtractor, children: renderItem }) {
|
|
31
|
+
const itemKeys = useItemKeys(componentName, data, keyExtractor);
|
|
32
|
+
return data.map((item, index)=>/*#__PURE__*/ _jsx(Fragment, {
|
|
33
|
+
children: renderItem({
|
|
34
|
+
item,
|
|
35
|
+
index
|
|
36
|
+
})
|
|
37
|
+
}, itemKeys[index]));
|
|
38
|
+
}
|
|
39
|
+
function RecycledItems({ data, keyExtractor, children: renderItem, overscanCount, estimatedItemSize = 64 }) {
|
|
40
|
+
const { itemKeys, revision, rows, onWindowChange } = useRecycledRows({
|
|
41
|
+
componentName,
|
|
42
|
+
Slot: LazyItemsSlotNativeView,
|
|
43
|
+
data,
|
|
44
|
+
keyExtractor,
|
|
45
|
+
renderItem,
|
|
46
|
+
overscanCount,
|
|
47
|
+
estimatedItemSize
|
|
48
|
+
});
|
|
49
|
+
return /*#__PURE__*/ _jsx(LazyItemsNativeView, {
|
|
50
|
+
itemKeys: itemKeys,
|
|
51
|
+
revision: revision,
|
|
52
|
+
estimatedItemSize: estimatedItemSize,
|
|
53
|
+
onWindowChange: ({ nativeEvent })=>onWindowChange(nativeEvent),
|
|
54
|
+
children: /*#__PURE__*/ _jsx(LazyItemsPoolNativeView, {
|
|
55
|
+
children: rows
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
Items.displayName = componentName;
|
|
60
|
+
return Items;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["jetpack-compose/LazyItems/index.tsx"],"sourcesContent":[null],"names":["requireNativeView","Fragment","useItemKeys","useRecycledRows","LazyItemsNativeView","LazyItemsSlotNativeView","LazyItemsPoolNativeView","LazyItems","createLazyItems","componentName","Items","recycling","props","RecycledItems","StaticItems","data","keyExtractor","children","renderItem","itemKeys","map","item","index","overscanCount","estimatedItemSize","revision","rows","onWindowChange","Slot","nativeEvent","displayName"],"mappings":";AAAA,SAASA,iBAAiB,QAAQ,OAAO;AACzC,SAASC,QAAQ,QAA2B,QAAQ;AAEpD,SACEC,WAAW,EACXC,eAAe,QAIV,kCAAkC;AA0CzC,MAAMC,sBACJJ,kBAAwC,UAAU;AACpD,MAAMK,0BACJL,kBAAqC,UAAU;AACjD,MAAMM,0BACJN,kBAAkB,UAAU;AAE9B;;;;;;;;;CASC,GACD,OAAO,MAAMO,YAAYC,gBAAgB,oBAAoB;AAE7D;;;CAGC,GACD,OAAO,SAASA,gBAAgBC,aAAqB;IACnD,SAASC,MAAa,EAAEC,YAAY,IAAI,EAAE,GAAGC,OAA8B;QACzE,OAAOD,0BAAY,KAACE;YAAe,GAAGD,KAAK;2BAAO,KAACE;YAAa,GAAGF,KAAK;;IAC1E;IAEA,2EAA2E;IAC3E,SAASE,YAAmB,EAC1BC,IAAI,EACJC,YAAY,EACZC,UAAUC,UAAU,EACqB;QACzC,MAAMC,WAAWjB,YAAYO,eAAeM,MAAMC;QAClD,OAAOD,KAAKK,GAAG,CAAC,CAACC,MAAMC,sBACrB,KAACrB;0BAAgCiB,WAAW;oBAAEG;oBAAMC;gBAAM;eAA3CH,QAAQ,CAACG,MAAM;IAElC;IAEA,SAAST,cAAqB,EAC5BE,IAAI,EACJC,YAAY,EACZC,UAAUC,UAAU,EACpBK,aAAa,EACbC,oBAAoB,EAAE,EACmB;QACzC,MAAM,EAAEL,QAAQ,EAAEM,QAAQ,EAAEC,IAAI,EAAEC,cAAc,EAAE,GAAGxB,gBAAgB;YACnEM;YACAmB,MAAMvB;YACNU;YACAC;YACAE;YACAK;YACAC;QACF;QAEA,qBACE,KAACpB;YACCe,UAAUA;YACVM,UAAUA;YACVD,mBAAmBA;YACnBG,gBAAgB,CAAC,EAAEE,WAAW,EAAE,GAAKF,eAAeE;sBACpD,cAAA,KAACvB;0BAAyBoB;;;IAGhC;IACAhB,MAAMoB,WAAW,GAAGrB;IACpB,OAAOC;AACT"}
|