@expo/ui 58.0.7 → 58.0.9
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 +12 -5
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/AnimatedVisibilityView.kt +40 -8
- package/android/src/main/java/expo/modules/ui/ComposeViews.kt +21 -3
- package/android/src/main/java/expo/modules/ui/DatePickerView.kt +12 -4
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +5 -1
- package/android/src/main/java/expo/modules/ui/HorizontalPagerView.kt +3 -1
- package/android/src/main/java/expo/modules/ui/HostView.kt +64 -12
- package/android/src/main/java/expo/modules/ui/LazyItemsView.kt +14 -2
- package/android/src/main/java/expo/modules/ui/ModalBottomSheetView.kt +5 -1
- package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +40 -7
- package/android/src/main/java/expo/modules/ui/RNHostView.kt +3 -1
- package/android/src/main/java/expo/modules/ui/SemanticsModifier.kt +2 -1
- package/android/src/main/java/expo/modules/ui/ShapeView.kt +3 -1
- package/android/src/main/java/expo/modules/ui/SlotView.kt +3 -1
- package/android/src/main/java/expo/modules/ui/SnackbarView.kt +5 -1
- package/android/src/main/java/expo/modules/ui/TextView.kt +3 -1
- package/android/src/main/java/expo/modules/ui/Utils.kt +3 -1
- package/android/src/main/java/expo/modules/ui/colors/MaterialColors.kt +5 -1
- package/android/src/main/java/expo/modules/ui/convertibles/AnimationSpecParams.kt +3 -1
- package/android/src/main/java/expo/modules/ui/graphics/ImageLoader.kt +6 -2
- package/android/src/main/java/expo/modules/ui/icon/IconView.kt +5 -1
- package/android/src/main/java/expo/modules/ui/state/ObservableState.kt +3 -1
- package/android/src/main/java/expo/modules/ui/textfield/BasicTextField.kt +10 -2
- package/android/src/main/java/expo/modules/ui/textfield/TextField.kt +20 -4
- package/android/src/main/java/expo/modules/ui/textfield/TextFieldShared.kt +3 -1
- package/build/jetpack-compose/LazyColumn/index.d.ts +2 -1
- package/build/jetpack-compose/LazyColumn/index.js +1 -0
- package/build/jetpack-compose/LazyColumn/index.js.map +1 -1
- package/build/jetpack-compose/LazyItems/index.d.ts +19 -18
- package/build/jetpack-compose/LazyItems/index.js +1 -2
- package/build/jetpack-compose/LazyItems/index.js.map +1 -1
- package/build/jetpack-compose/LazyRow/index.d.ts +2 -1
- package/build/jetpack-compose/LazyRow/index.js +1 -0
- package/build/jetpack-compose/LazyRow/index.js.map +1 -1
- package/build/jetpack-compose/index.d.ts +0 -1
- package/build/jetpack-compose/index.js.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +33 -6
- package/build/jetpack-compose/modifiers/index.js +15 -2
- package/build/jetpack-compose/modifiers/index.js.map +1 -1
- package/build/swift-ui/LazyHStack/index.d.ts +45 -0
- package/build/swift-ui/LazyHStack/index.js +9 -0
- package/build/swift-ui/LazyHStack/index.js.map +1 -1
- package/build/swift-ui/LazyStackForEach/index.d.ts +44 -0
- package/build/swift-ui/LazyStackForEach/index.js +54 -0
- package/build/swift-ui/LazyStackForEach/index.js.map +1 -0
- package/build/swift-ui/LazyVStack/index.d.ts +45 -0
- package/build/swift-ui/LazyVStack/index.js +9 -0
- package/build/swift-ui/LazyVStack/index.js.map +1 -1
- package/build/swift-ui/List/DataListForEach.d.ts +6 -7
- package/build/swift-ui/List/DataListForEach.js.map +1 -1
- package/build/swift-ui/List/ListForEach.d.ts +7 -1
- package/build/swift-ui/List/ListForEach.js +1 -5
- package/build/swift-ui/List/ListForEach.js.map +1 -1
- package/build/swift-ui/index.d.ts +1 -0
- package/build/swift-ui/index.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/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/Switch/index.android.js +5 -1
- package/build/universal/Switch/index.android.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 +0 -1
- package/ios/DataListForEachView.swift +65 -28
- package/ios/LazyHStackView.swift +3 -0
- package/ios/LazyVStackView.swift +3 -0
- package/ios/ListView.swift +8 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.7/expo.modules.ui-58.0.7-sources.jar → 58.0.9/expo.modules.ui-58.0.9-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.7/expo.modules.ui-58.0.7.module → 58.0.9/expo.modules.ui-58.0.9.module} +23 -23
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.7/expo.modules.ui-58.0.7.pom → 58.0.9/expo.modules.ui-58.0.9.pom} +2 -2
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.9/expo.modules.ui-58.0.9.pom.sha512 +1 -0
- package/package.json +3 -3
- 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 +2 -0
- package/src/jetpack-compose/LazyItems/index.tsx +18 -21
- package/src/jetpack-compose/LazyRow/index.tsx +2 -0
- package/src/jetpack-compose/index.ts +0 -1
- package/src/jetpack-compose/modifiers/index.ts +32 -4
- package/src/swift-ui/LazyHStack/index.tsx +45 -0
- package/src/swift-ui/LazyStackForEach/index.tsx +110 -0
- package/src/swift-ui/LazyVStack/index.tsx +45 -0
- package/src/swift-ui/List/DataListForEach.tsx +7 -8
- package/src/swift-ui/List/ListForEach.tsx +10 -3
- package/src/swift-ui/index.tsx +1 -0
- package/src/swift-ui/modifiers/index.ts +5 -1
- 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/Switch/index.android.tsx +11 -2
- package/src/universal/types.ts +27 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.7/expo.modules.ui-58.0.7.pom.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +0 -13
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 58.0.9
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Patch Changes
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Force-bump all packages, due to migration to changesets. ([#50762](https://github.com/expo/expo/pull/50762) by [@kitten](https://github.com/kitten))
|
|
8
|
+
- [iOS] Added `LazyVStack.ForEach` and `LazyHStack.ForEach`, 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 stacks only render the rows near the viewport. Set `recycling={false}` to render every row. ([#50579](https://github.com/expo/expo/pull/50579) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
9
|
+
- [android] Fix `Switch` label rendering one letter per line inside a `Host` with `matchContents`. ([#50693](https://github.com/expo/expo/pull/50693) by [@janicduplessis](https://github.com/janicduplessis))
|
|
10
|
+
- [android] Added `IntrinsicSize` support to the `width` modifier. ([#50693](https://github.com/expo/expo/pull/50693) by [@janicduplessis](https://github.com/janicduplessis))
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
## 58.0.8 — 2026-09-28
|
|
10
13
|
|
|
11
|
-
###
|
|
14
|
+
### 🎉 New features
|
|
15
|
+
|
|
16
|
+
- [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))
|
|
17
|
+
- [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))
|
|
18
|
+
- 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))
|
|
12
19
|
|
|
13
20
|
## 58.0.7 — 2026-09-25
|
|
14
21
|
|
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.9'
|
|
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.9"
|
|
22
22
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
23
23
|
}
|
|
24
24
|
buildFeatures {
|
|
@@ -73,32 +73,64 @@ data class ExitTransitionRecord(
|
|
|
73
73
|
// TODO(@ubax): expose animationSpec parameter (tween, spring, duration) for all transitions
|
|
74
74
|
private fun EnterTransitionRecord.toComposeTransition(): EnterTransition = when (type) {
|
|
75
75
|
EnterTransitionType.FADE_IN ->
|
|
76
|
-
if (initialAlpha != null)
|
|
76
|
+
if (initialAlpha != null) {
|
|
77
|
+
fadeIn(initialAlpha = initialAlpha)
|
|
78
|
+
} else {
|
|
79
|
+
fadeIn()
|
|
80
|
+
}
|
|
77
81
|
EnterTransitionType.SLIDE_IN_HORIZONTALLY ->
|
|
78
|
-
if (initialOffsetX != null)
|
|
82
|
+
if (initialOffsetX != null) {
|
|
83
|
+
slideInHorizontally { (it * initialOffsetX).toInt() }
|
|
84
|
+
} else {
|
|
85
|
+
slideInHorizontally()
|
|
86
|
+
}
|
|
79
87
|
EnterTransitionType.SLIDE_IN_VERTICALLY ->
|
|
80
|
-
if (initialOffsetY != null)
|
|
88
|
+
if (initialOffsetY != null) {
|
|
89
|
+
slideInVertically { (it * initialOffsetY).toInt() }
|
|
90
|
+
} else {
|
|
91
|
+
slideInVertically()
|
|
92
|
+
}
|
|
81
93
|
// TODO(@ubax): expose expandFrom (Alignment) and initialSize parameters for expand transitions
|
|
82
94
|
EnterTransitionType.EXPAND_IN -> expandIn()
|
|
83
95
|
EnterTransitionType.EXPAND_HORIZONTALLY -> expandHorizontally()
|
|
84
96
|
EnterTransitionType.EXPAND_VERTICALLY -> expandVertically()
|
|
85
97
|
EnterTransitionType.SCALE_IN ->
|
|
86
|
-
if (initialScale != null)
|
|
98
|
+
if (initialScale != null) {
|
|
99
|
+
scaleIn(initialScale = initialScale)
|
|
100
|
+
} else {
|
|
101
|
+
scaleIn()
|
|
102
|
+
}
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
private fun ExitTransitionRecord.toComposeTransition(): ExitTransition = when (type) {
|
|
90
106
|
ExitTransitionType.FADE_OUT ->
|
|
91
|
-
if (targetAlpha != null)
|
|
107
|
+
if (targetAlpha != null) {
|
|
108
|
+
fadeOut(targetAlpha = targetAlpha)
|
|
109
|
+
} else {
|
|
110
|
+
fadeOut()
|
|
111
|
+
}
|
|
92
112
|
ExitTransitionType.SLIDE_OUT_HORIZONTALLY ->
|
|
93
|
-
if (targetOffsetX != null)
|
|
113
|
+
if (targetOffsetX != null) {
|
|
114
|
+
slideOutHorizontally { (it * targetOffsetX).toInt() }
|
|
115
|
+
} else {
|
|
116
|
+
slideOutHorizontally()
|
|
117
|
+
}
|
|
94
118
|
ExitTransitionType.SLIDE_OUT_VERTICALLY ->
|
|
95
|
-
if (targetOffsetY != null)
|
|
119
|
+
if (targetOffsetY != null) {
|
|
120
|
+
slideOutVertically { (it * targetOffsetY).toInt() }
|
|
121
|
+
} else {
|
|
122
|
+
slideOutVertically()
|
|
123
|
+
}
|
|
96
124
|
// TODO(@ubax): expose shrinkTowards (Alignment) and targetSize parameters for shrink transitions
|
|
97
125
|
ExitTransitionType.SHRINK_OUT -> shrinkOut()
|
|
98
126
|
ExitTransitionType.SHRINK_HORIZONTALLY -> shrinkHorizontally()
|
|
99
127
|
ExitTransitionType.SHRINK_VERTICALLY -> shrinkVertically()
|
|
100
128
|
ExitTransitionType.SCALE_OUT ->
|
|
101
|
-
if (targetScale != null)
|
|
129
|
+
if (targetScale != null) {
|
|
130
|
+
scaleOut(targetScale = targetScale)
|
|
131
|
+
} else {
|
|
132
|
+
scaleOut()
|
|
133
|
+
}
|
|
102
134
|
}
|
|
103
135
|
|
|
104
136
|
private fun List<EnterTransitionRecord>.toComposedEnterTransition(): EnterTransition? =
|
|
@@ -65,7 +65,13 @@ internal fun FunctionalComposableScope.RowContent(props: LayoutProps) {
|
|
|
65
65
|
verticalAlignment = props.verticalAlignment?.toComposeAlignment() ?: Alignment.Top,
|
|
66
66
|
modifier = ModifierRegistry
|
|
67
67
|
.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
|
|
68
|
-
.then(
|
|
68
|
+
.then(
|
|
69
|
+
if (scrollBehavior != null) {
|
|
70
|
+
Modifier.nestedScroll(scrollBehavior)
|
|
71
|
+
} else {
|
|
72
|
+
Modifier
|
|
73
|
+
}
|
|
74
|
+
)
|
|
69
75
|
) {
|
|
70
76
|
Children(UIComposableScope(rowScope = this@Row, nestedScrollConnection = scrollBehavior))
|
|
71
77
|
}
|
|
@@ -95,7 +101,13 @@ internal fun FunctionalComposableScope.ColumnContent(props: LayoutProps) {
|
|
|
95
101
|
horizontalAlignment = props.horizontalAlignment?.toComposeAlignment() ?: Alignment.Start,
|
|
96
102
|
modifier = ModifierRegistry
|
|
97
103
|
.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
|
|
98
|
-
.then(
|
|
104
|
+
.then(
|
|
105
|
+
if (scrollBehavior != null) {
|
|
106
|
+
Modifier.nestedScroll(scrollBehavior)
|
|
107
|
+
} else {
|
|
108
|
+
Modifier
|
|
109
|
+
}
|
|
110
|
+
)
|
|
99
111
|
) {
|
|
100
112
|
Children(UIComposableScope(columnScope = this@Column, nestedScrollConnection = scrollBehavior))
|
|
101
113
|
}
|
|
@@ -112,7 +124,13 @@ fun FunctionalComposableScope.BoxContent(props: LayoutProps) {
|
|
|
112
124
|
contentAlignment = props.contentAlignment?.toComposeAlignment() ?: Alignment.TopStart,
|
|
113
125
|
modifier = ModifierRegistry
|
|
114
126
|
.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)
|
|
115
|
-
.then(
|
|
127
|
+
.then(
|
|
128
|
+
if (scrollBehavior != null) {
|
|
129
|
+
Modifier.nestedScroll(scrollBehavior)
|
|
130
|
+
} else {
|
|
131
|
+
Modifier
|
|
132
|
+
}
|
|
133
|
+
)
|
|
116
134
|
) {
|
|
117
135
|
Children(UIComposableScope(boxScope = this@Box, nestedScrollConnection = scrollBehavior))
|
|
118
136
|
}
|
|
@@ -219,14 +219,22 @@ fun rememberSelectableDates(selectableDatesRecord: SelectableDatesRecord?): Sele
|
|
|
219
219
|
|
|
220
220
|
object : SelectableDates {
|
|
221
221
|
override fun isSelectableDate(utcTimeMillis: Long): Boolean {
|
|
222
|
-
if (startUtcDayMillis != null && utcTimeMillis < startUtcDayMillis)
|
|
223
|
-
|
|
222
|
+
if (startUtcDayMillis != null && utcTimeMillis < startUtcDayMillis) {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
if (endUtcDayMillis != null && utcTimeMillis > endUtcDayMillis) {
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
224
228
|
return true
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
override fun isSelectableYear(year: Int): Boolean {
|
|
228
|
-
if (startYear != null && year < startYear)
|
|
229
|
-
|
|
232
|
+
if (startYear != null && year < startYear) {
|
|
233
|
+
return false
|
|
234
|
+
}
|
|
235
|
+
if (endYear != null && year > endYear) {
|
|
236
|
+
return false
|
|
237
|
+
}
|
|
230
238
|
return true
|
|
231
239
|
}
|
|
232
240
|
}
|
|
@@ -167,7 +167,11 @@ class ExpoUIModule : Module() {
|
|
|
167
167
|
?: appContext.reactContext
|
|
168
168
|
?: throw Exceptions.ReactContextLost()
|
|
169
169
|
val resolvedScheme = options?.scheme
|
|
170
|
-
?: if (context.isSystemInDarkTheme())
|
|
170
|
+
?: if (context.isSystemInDarkTheme()) {
|
|
171
|
+
ExpoColorScheme.DARK
|
|
172
|
+
} else {
|
|
173
|
+
ExpoColorScheme.LIGHT
|
|
174
|
+
}
|
|
171
175
|
val isDark = resolvedScheme == ExpoColorScheme.DARK
|
|
172
176
|
val seedArgb = options?.seedColor?.composeOrNull?.toArgb()
|
|
173
177
|
val colorScheme = if (seedArgb != null) {
|
|
@@ -125,7 +125,9 @@ fun FunctionalComposableScope.HorizontalPagerContent(
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
val pageCount = pageCountState.intValue
|
|
128
|
-
if (pageCount == 0)
|
|
128
|
+
if (pageCount == 0) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
129
131
|
|
|
130
132
|
// Mirror Compose's PagerState observable fields to JS callbacks. Each
|
|
131
133
|
// state-backed snapshotFlow drops its first emission so we don't echo the
|
|
@@ -81,17 +81,33 @@ internal enum class ExpoColorScheme(val value: String) : Enumerable {
|
|
|
81
81
|
|
|
82
82
|
fun toColorScheme(context: Context): ColorScheme {
|
|
83
83
|
return when (this) {
|
|
84
|
-
LIGHT -> if (isDynamicColorSupported)
|
|
85
|
-
|
|
84
|
+
LIGHT -> if (isDynamicColorSupported) {
|
|
85
|
+
dynamicLightColorScheme(context)
|
|
86
|
+
} else {
|
|
87
|
+
lightColorScheme()
|
|
88
|
+
}
|
|
89
|
+
DARK -> if (isDynamicColorSupported) {
|
|
90
|
+
dynamicDarkColorScheme(context)
|
|
91
|
+
} else {
|
|
92
|
+
darkColorScheme()
|
|
93
|
+
}
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
companion object {
|
|
90
98
|
fun defaultColorScheme(context: Context, isSystemInDarkTheme: Boolean): ColorScheme {
|
|
91
99
|
return if (isDynamicColorSupported) {
|
|
92
|
-
if (isSystemInDarkTheme)
|
|
100
|
+
if (isSystemInDarkTheme) {
|
|
101
|
+
dynamicDarkColorScheme(context)
|
|
102
|
+
} else {
|
|
103
|
+
dynamicLightColorScheme(context)
|
|
104
|
+
}
|
|
93
105
|
} else {
|
|
94
|
-
if (isSystemInDarkTheme)
|
|
106
|
+
if (isSystemInDarkTheme) {
|
|
107
|
+
darkColorScheme()
|
|
108
|
+
} else {
|
|
109
|
+
lightColorScheme()
|
|
110
|
+
}
|
|
95
111
|
}
|
|
96
112
|
}
|
|
97
113
|
}
|
|
@@ -159,8 +175,20 @@ internal class HostView(context: Context, appContext: AppContext) :
|
|
|
159
175
|
|
|
160
176
|
Layout(
|
|
161
177
|
modifier = Modifier
|
|
162
|
-
.then(
|
|
163
|
-
|
|
178
|
+
.then(
|
|
179
|
+
if (props.matchContentsHorizontal.value == true) {
|
|
180
|
+
Modifier.wrapContentWidth()
|
|
181
|
+
} else {
|
|
182
|
+
Modifier
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
.then(
|
|
186
|
+
if (props.matchContentsVertical.value == true) {
|
|
187
|
+
Modifier.wrapContentHeight()
|
|
188
|
+
} else {
|
|
189
|
+
Modifier
|
|
190
|
+
}
|
|
191
|
+
)
|
|
164
192
|
.onSizeChanged { size -> dispatchOnLayoutContent(size, density) },
|
|
165
193
|
content = content
|
|
166
194
|
) { measurables, constraints ->
|
|
@@ -199,8 +227,16 @@ internal class HostView(context: Context, appContext: AppContext) :
|
|
|
199
227
|
val heightDp = contentHeightPx.toDp().value.toDouble()
|
|
200
228
|
|
|
201
229
|
shadowNodeProxy.setViewSize(
|
|
202
|
-
if (constraints.maxWidth == 0)
|
|
203
|
-
|
|
230
|
+
if (constraints.maxWidth == 0) {
|
|
231
|
+
widthDp
|
|
232
|
+
} else {
|
|
233
|
+
Double.NaN
|
|
234
|
+
},
|
|
235
|
+
if (constraints.maxHeight == 0) {
|
|
236
|
+
heightDp
|
|
237
|
+
} else {
|
|
238
|
+
Double.NaN
|
|
239
|
+
}
|
|
204
240
|
)
|
|
205
241
|
}
|
|
206
242
|
}
|
|
@@ -227,8 +263,16 @@ internal class HostView(context: Context, appContext: AppContext) :
|
|
|
227
263
|
val height = size.height.toDp().value
|
|
228
264
|
|
|
229
265
|
if (matchContentsHorizontal == true || matchContentsVertical == true) {
|
|
230
|
-
val styleWidth = if (matchContentsHorizontal == true && width > 0)
|
|
231
|
-
|
|
266
|
+
val styleWidth = if (matchContentsHorizontal == true && width > 0) {
|
|
267
|
+
width
|
|
268
|
+
} else {
|
|
269
|
+
null
|
|
270
|
+
}
|
|
271
|
+
val styleHeight = if (matchContentsVertical == true && height > 0) {
|
|
272
|
+
height
|
|
273
|
+
} else {
|
|
274
|
+
null
|
|
275
|
+
}
|
|
232
276
|
shadowNodeProxy.setStyleSize(styleWidth?.toDouble(), styleHeight?.toDouble())
|
|
233
277
|
}
|
|
234
278
|
|
|
@@ -263,8 +307,16 @@ internal class HostView(context: Context, appContext: AppContext) :
|
|
|
263
307
|
val matchContentsVertical = props.matchContentsVertical.value
|
|
264
308
|
val composeView = findComposeView()
|
|
265
309
|
composeView.layoutParams = LayoutParams(
|
|
266
|
-
if (matchContentsHorizontal == true)
|
|
267
|
-
|
|
310
|
+
if (matchContentsHorizontal == true) {
|
|
311
|
+
LayoutParams.WRAP_CONTENT
|
|
312
|
+
} else {
|
|
313
|
+
LayoutParams.MATCH_PARENT
|
|
314
|
+
},
|
|
315
|
+
if (matchContentsVertical == true) {
|
|
316
|
+
LayoutParams.WRAP_CONTENT
|
|
317
|
+
} else {
|
|
318
|
+
LayoutParams.MATCH_PARENT
|
|
319
|
+
}
|
|
268
320
|
)
|
|
269
321
|
}
|
|
270
322
|
|
|
@@ -176,7 +176,15 @@ internal fun LazyListScope.lazyRecycledItems(
|
|
|
176
176
|
Box(
|
|
177
177
|
modifier = Modifier.onSizeChanged { size ->
|
|
178
178
|
if (content != null) {
|
|
179
|
-
window.measure(
|
|
179
|
+
window.measure(
|
|
180
|
+
itemKey,
|
|
181
|
+
if (isVertical) {
|
|
182
|
+
size.height
|
|
183
|
+
} else {
|
|
184
|
+
size.width
|
|
185
|
+
},
|
|
186
|
+
revision
|
|
187
|
+
)
|
|
180
188
|
}
|
|
181
189
|
}
|
|
182
190
|
) {
|
|
@@ -205,7 +213,11 @@ internal fun LazyListScope.lazyRecycledItems(
|
|
|
205
213
|
*/
|
|
206
214
|
internal fun Modifier.lazyRecycledItemsCrossAxis(list: ViewGroup, isVertical: Boolean): Modifier =
|
|
207
215
|
layout { measurable, constraints ->
|
|
208
|
-
val crossAxisSize = if (isVertical)
|
|
216
|
+
val crossAxisSize = if (isVertical) {
|
|
217
|
+
constraints.maxWidth
|
|
218
|
+
} else {
|
|
219
|
+
constraints.maxHeight
|
|
220
|
+
}
|
|
209
221
|
for (index in 0..<list.childCount) {
|
|
210
222
|
(list.getChildAt(index) as? LazyItemsView)?.window?.updateCrossAxisSize(crossAxisSize)
|
|
211
223
|
}
|
|
@@ -145,7 +145,11 @@ fun FunctionalComposableScope.ModalBottomSheetContent(
|
|
|
145
145
|
// then asked for light system bars, which turned the navigation bar white.
|
|
146
146
|
val resolvedContentColor = props.contentColor.composeOrNull
|
|
147
147
|
?: MaterialTheme.colorScheme.contentColorFor(resolvedContainerColor).takeOrElse {
|
|
148
|
-
if (resolvedContainerColor.luminance() > 0.5f)
|
|
148
|
+
if (resolvedContainerColor.luminance() > 0.5f) {
|
|
149
|
+
ComposeColor.Black
|
|
150
|
+
} else {
|
|
151
|
+
ComposeColor.White
|
|
152
|
+
}
|
|
149
153
|
}
|
|
150
154
|
val resolvedScrimColor = props.scrimColor.composeOrNull ?: BottomSheetDefaults.ScrimColor
|
|
151
155
|
val dragHandleSlotView = findChildSlotView(view, "dragHandle")
|
|
@@ -21,6 +21,7 @@ import androidx.compose.foundation.border
|
|
|
21
21
|
import androidx.compose.foundation.clickable
|
|
22
22
|
import androidx.compose.foundation.combinedClickable
|
|
23
23
|
import androidx.compose.foundation.horizontalScroll
|
|
24
|
+
import androidx.compose.foundation.layout.IntrinsicSize
|
|
24
25
|
import androidx.compose.foundation.layout.defaultMinSize
|
|
25
26
|
import androidx.compose.foundation.layout.fillMaxHeight
|
|
26
27
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
@@ -67,6 +68,7 @@ import androidx.compose.ui.layout.onVisibilityChanged
|
|
|
67
68
|
import androidx.compose.ui.layout.positionInWindow
|
|
68
69
|
import androidx.compose.ui.platform.LocalDensity
|
|
69
70
|
import androidx.compose.ui.semantics.Role
|
|
71
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
70
72
|
import androidx.compose.ui.semantics.contentType
|
|
71
73
|
import androidx.compose.ui.semantics.semantics
|
|
72
74
|
import androidx.compose.ui.unit.DpOffset
|
|
@@ -78,6 +80,7 @@ import expo.modules.kotlin.records.Field
|
|
|
78
80
|
import expo.modules.kotlin.records.Record
|
|
79
81
|
import expo.modules.kotlin.records.recordFromMap
|
|
80
82
|
import expo.modules.kotlin.types.ConverterContext
|
|
83
|
+
import expo.modules.kotlin.types.Either
|
|
81
84
|
import expo.modules.kotlin.types.Enumerable
|
|
82
85
|
import expo.modules.kotlin.types.OptimizedRecord
|
|
83
86
|
import expo.modules.kotlin.views.ComposableScope
|
|
@@ -132,6 +135,21 @@ data class WidthParams(
|
|
|
132
135
|
@Field val width: Int = 0
|
|
133
136
|
) : Record
|
|
134
137
|
|
|
138
|
+
internal enum class IntrinsicSizeType(val value: String) : Enumerable {
|
|
139
|
+
MIN("min"),
|
|
140
|
+
MAX("max");
|
|
141
|
+
|
|
142
|
+
fun toComposeIntrinsicSize(): IntrinsicSize = when (this) {
|
|
143
|
+
MIN -> IntrinsicSize.Min
|
|
144
|
+
MAX -> IntrinsicSize.Max
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@OptimizedRecord
|
|
149
|
+
internal data class ComposeWidthParams(
|
|
150
|
+
@Field val width: Either<Int, IntrinsicSizeType>? = null
|
|
151
|
+
) : Record
|
|
152
|
+
|
|
135
153
|
@OptimizedRecord
|
|
136
154
|
data class HeightParams(
|
|
137
155
|
@Field val height: Int = 0
|
|
@@ -167,7 +185,9 @@ data class BackgroundParams(
|
|
|
167
185
|
// Color animation specs reuse the JS `$type` shape from `@expo/ui/jetpack-compose/modifiers/animation` (spring / tween / snap).
|
|
168
186
|
// Keyframes are float-only and aren't supported for colors.
|
|
169
187
|
private fun parseColorAnimationSpec(raw: Any?): AnimationSpec<androidx.compose.ui.graphics.Color>? {
|
|
170
|
-
if (raw !is Map<*, *>)
|
|
188
|
+
if (raw !is Map<*, *>) {
|
|
189
|
+
return null
|
|
190
|
+
}
|
|
171
191
|
return when (raw["\$type"]) {
|
|
172
192
|
"spring" -> spring(
|
|
173
193
|
dampingRatio = (raw["dampingRatio"] as? Number)?.toFloat() ?: Spring.DampingRatioNoBouncy,
|
|
@@ -408,7 +428,9 @@ object ModifierRegistry {
|
|
|
408
428
|
scope: ComposableScope,
|
|
409
429
|
eventDispatcher: ModifierEventDispatcher
|
|
410
430
|
): Modifier {
|
|
411
|
-
if (modifiers.isNullOrEmpty())
|
|
431
|
+
if (modifiers.isNullOrEmpty()) {
|
|
432
|
+
return Modifier
|
|
433
|
+
}
|
|
412
434
|
return modifiers.fold(Modifier as Modifier) { acc, config ->
|
|
413
435
|
val type = config["\$type"]?.asString() ?: return@fold acc
|
|
414
436
|
val modifier = modifierFactories[type]?.invoke(config, scope, appContext, eventDispatcher)
|
|
@@ -470,8 +492,12 @@ object ModifierRegistry {
|
|
|
470
492
|
}
|
|
471
493
|
|
|
472
494
|
register("width") { map, _, appContext, _ ->
|
|
473
|
-
val
|
|
474
|
-
|
|
495
|
+
val width = recordFromMap<ComposeWidthParams>(map, appContext).width
|
|
496
|
+
if (width?.`is`(IntrinsicSizeType::class) == true) {
|
|
497
|
+
Modifier.width(width.second().toComposeIntrinsicSize())
|
|
498
|
+
} else {
|
|
499
|
+
Modifier.width((width?.first() ?: 0).dp)
|
|
500
|
+
}
|
|
475
501
|
}
|
|
476
502
|
|
|
477
503
|
register("height") { map, _, appContext, _ ->
|
|
@@ -681,9 +707,16 @@ object ModifierRegistry {
|
|
|
681
707
|
|
|
682
708
|
register("semantics") { map, _, appContext, _ ->
|
|
683
709
|
val params = recordFromMap<SemanticsParams>(map, appContext)
|
|
684
|
-
params.contentType.toContentType()
|
|
685
|
-
|
|
686
|
-
|
|
710
|
+
val type = params.contentType.toContentType()
|
|
711
|
+
val description = params.contentDescription
|
|
712
|
+
if (type == null && description == null) {
|
|
713
|
+
Modifier
|
|
714
|
+
} else {
|
|
715
|
+
Modifier.semantics {
|
|
716
|
+
type?.let { contentType = it }
|
|
717
|
+
description?.let { contentDescription = it }
|
|
718
|
+
}
|
|
719
|
+
}
|
|
687
720
|
}
|
|
688
721
|
|
|
689
722
|
register("clip") { map, _, appContext, _ ->
|
|
@@ -498,7 +498,9 @@ private class TouchDispatchingRootViewGroup(
|
|
|
498
498
|
// Use the (…, type, consumed) variant so we can read how much the sheet ate (consumed[1]).
|
|
499
499
|
val consumed = IntArray(2)
|
|
500
500
|
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, ViewCompat.TYPE_TOUCH, consumed)
|
|
501
|
-
if (consumed[1] != 0)
|
|
501
|
+
if (consumed[1] != 0) {
|
|
502
|
+
sheetMovingOnLastDragFrame = true
|
|
503
|
+
}
|
|
502
504
|
}
|
|
503
505
|
|
|
504
506
|
override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
|
|
@@ -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) {
|
|
@@ -179,7 +179,9 @@ fun pathFromShapeRecord(record: ShapeRecord, size: Size, density: Density): Path
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
fun shapeFromShapeRecord(shapeRecord: ShapeRecord?): Shape? {
|
|
182
|
-
if (shapeRecord == null)
|
|
182
|
+
if (shapeRecord == null) {
|
|
183
|
+
return null
|
|
184
|
+
}
|
|
183
185
|
return object : Shape {
|
|
184
186
|
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
|
|
185
187
|
val path = pathFromShapeRecord(shapeRecord, size, density)
|
|
@@ -65,7 +65,9 @@ fun findChildSlotView(viewGroup: ViewGroup, slotName: String): SlotView? {
|
|
|
65
65
|
inline fun <reified T> findChildOfType(viewGroup: ViewGroup): T? {
|
|
66
66
|
for (index in 0..<viewGroup.size) {
|
|
67
67
|
val child = viewGroup.getChildAt(index)
|
|
68
|
-
if (child is T)
|
|
68
|
+
if (child is T) {
|
|
69
|
+
return child
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
72
|
return null
|
|
71
73
|
}
|
|
@@ -83,7 +83,11 @@ fun FunctionalComposableScope.SnackbarHostContent(
|
|
|
83
83
|
"long" -> SnackbarDuration.Long
|
|
84
84
|
"indefinite" -> SnackbarDuration.Indefinite
|
|
85
85
|
// M3 default: indefinite when there's an action label, else short.
|
|
86
|
-
else -> if (options.actionLabel == null)
|
|
86
|
+
else -> if (options.actionLabel == null) {
|
|
87
|
+
SnackbarDuration.Short
|
|
88
|
+
} else {
|
|
89
|
+
SnackbarDuration.Indefinite
|
|
90
|
+
}
|
|
87
91
|
}
|
|
88
92
|
val result = try {
|
|
89
93
|
withContext(scope.coroutineContext) {
|
|
@@ -134,7 +134,9 @@ enum class TextLineBreakType(val value: String) : Enumerable {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
fun resolveFontFamily(name: String?, context: Context): FontFamily? {
|
|
137
|
-
if (name == null)
|
|
137
|
+
if (name == null) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
138
140
|
return when (name) {
|
|
139
141
|
"default" -> FontFamily.Default
|
|
140
142
|
"sansSerif" -> FontFamily.SansSerif
|
|
@@ -32,7 +32,9 @@ val Color?.composeOrNull: androidx.compose.ui.graphics.Color?
|
|
|
32
32
|
* Gets the ImageVector for a given icon name using reflection.
|
|
33
33
|
*/
|
|
34
34
|
fun getImageVector(icon: String?): ImageVector? {
|
|
35
|
-
if (icon.isNullOrEmpty())
|
|
35
|
+
if (icon.isNullOrEmpty()) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
36
38
|
return try {
|
|
37
39
|
val (theme, name) = icon.split(".")
|
|
38
40
|
val clazz = Class.forName("androidx.compose.material.icons.$theme.${name}Kt")
|
|
@@ -38,7 +38,11 @@ internal fun Context.isSystemInDarkTheme(): Boolean {
|
|
|
38
38
|
* Allows `expo-widgets` to back `getMaterialColors` inside the widgets JS runtime.
|
|
39
39
|
*/
|
|
40
40
|
fun getMaterialColorTokens(context: Context, isDark: Boolean): Map<String, String> {
|
|
41
|
-
val scheme = if (isDark)
|
|
41
|
+
val scheme = if (isDark) {
|
|
42
|
+
ExpoColorScheme.DARK
|
|
43
|
+
} else {
|
|
44
|
+
ExpoColorScheme.LIGHT
|
|
45
|
+
}
|
|
42
46
|
return scheme.toColorScheme(context).toTokenMap()
|
|
43
47
|
}
|
|
44
48
|
|
|
@@ -87,7 +87,9 @@ internal data class KeyframesSpecParams(
|
|
|
87
87
|
|
|
88
88
|
@Suppress("UNCHECKED_CAST")
|
|
89
89
|
internal fun parseAnimationSpec(raw: Any?, converterContext: ConverterContext): AnimationSpec<Float>? {
|
|
90
|
-
if (raw !is Map<*, *>)
|
|
90
|
+
if (raw !is Map<*, *>) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
91
93
|
val map = raw as Map<String, Any?>
|
|
92
94
|
return when (raw["\$type"]) {
|
|
93
95
|
"spring" -> recordFromMap<SpringSpecParams>(map, converterContext).toAnimationSpec()
|
|
@@ -199,7 +199,9 @@ class ImageLoader(
|
|
|
199
199
|
* Detect if byte array contains XML content.
|
|
200
200
|
*/
|
|
201
201
|
private fun isXmlContent(bytes: ByteArray): Boolean {
|
|
202
|
-
if (bytes.size < 5)
|
|
202
|
+
if (bytes.size < 5) {
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
203
205
|
|
|
204
206
|
// Check for UTF-8 BOM
|
|
205
207
|
var offset = 0
|
|
@@ -211,7 +213,9 @@ class ImageLoader(
|
|
|
211
213
|
// Check if content starts with '<' (possibly with leading whitespace)
|
|
212
214
|
for (i in offset until minOf(offset + 10, bytes.size)) {
|
|
213
215
|
val b = bytes[i]
|
|
214
|
-
if (b == '<'.code.toByte())
|
|
216
|
+
if (b == '<'.code.toByte()) {
|
|
217
|
+
return true
|
|
218
|
+
}
|
|
215
219
|
if (b != ' '.code.toByte() && b != '\t'.code.toByte() &&
|
|
216
220
|
b != '\n'.code.toByte() && b != '\r'.code.toByte()
|
|
217
221
|
) {
|
|
@@ -83,7 +83,11 @@ class IconView(context: Context, appContext: AppContext) :
|
|
|
83
83
|
// Render icon if painter available
|
|
84
84
|
if (painter != null) {
|
|
85
85
|
val resolvedTint = tint?.compose
|
|
86
|
-
?: if (inheritTint)
|
|
86
|
+
?: if (inheritTint) {
|
|
87
|
+
LocalContentColor.current
|
|
88
|
+
} else {
|
|
89
|
+
androidx.compose.ui.graphics.Color.Unspecified
|
|
90
|
+
}
|
|
87
91
|
Icon(
|
|
88
92
|
painter = painter,
|
|
89
93
|
contentDescription = contentDescription,
|
|
@@ -19,7 +19,9 @@ class ObservableState(initialValue: Any? = null) : SharedObject() {
|
|
|
19
19
|
set(v) {
|
|
20
20
|
_state.value = v
|
|
21
21
|
// Skip re-invoking onChange if state.value was written from inside onChange.
|
|
22
|
-
if (isNotifying)
|
|
22
|
+
if (isNotifying) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
23
25
|
isNotifying = true
|
|
24
26
|
try {
|
|
25
27
|
onChange?.invoke(v)
|