@expo/ui 56.0.7 → 56.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 +39 -1
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +44 -3
- package/android/src/main/java/expo/modules/ui/HostView.kt +2 -0
- package/android/src/main/java/expo/modules/ui/LoadingView.kt +80 -0
- package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +50 -4
- package/android/src/main/java/expo/modules/ui/RNHostView.kt +8 -3
- package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +28 -0
- package/android/src/main/java/expo/modules/ui/SnackbarView.kt +126 -0
- package/android/src/main/java/expo/modules/ui/state/ObservableState.kt +10 -0
- package/assets/keyboard_arrow_down.xml +10 -0
- package/build/State/useNativeState.d.ts +32 -3
- package/build/State/useNativeState.d.ts.map +1 -1
- package/build/community/bottom-sheet/BottomSheet.ios.d.ts.map +1 -1
- package/build/community/menu/MenuView.android.d.ts +16 -0
- package/build/community/menu/MenuView.android.d.ts.map +1 -0
- package/build/community/menu/MenuView.d.ts +19 -0
- package/build/community/menu/MenuView.d.ts.map +1 -0
- package/build/community/menu/MenuView.ios.d.ts +10 -0
- package/build/community/menu/MenuView.ios.d.ts.map +1 -0
- package/build/community/menu/index.d.ts +5 -0
- package/build/community/menu/index.d.ts.map +1 -0
- package/build/community/menu/types.d.ts +166 -0
- package/build/community/menu/types.d.ts.map +1 -0
- package/build/jetpack-compose/LoadingIndicator/index.d.ts +41 -0
- package/build/jetpack-compose/LoadingIndicator/index.d.ts.map +1 -0
- package/build/jetpack-compose/Snackbar/index.d.ts +94 -0
- package/build/jetpack-compose/Snackbar/index.d.ts.map +1 -0
- package/build/jetpack-compose/index.d.ts +2 -0
- package/build/jetpack-compose/index.d.ts.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +21 -2
- package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
- package/build/swift-ui/Alert/index.d.ts +42 -0
- package/build/swift-ui/Alert/index.d.ts.map +1 -0
- package/build/swift-ui/BottomSheet/index.d.ts +5 -1
- package/build/swift-ui/BottomSheet/index.d.ts.map +1 -1
- package/build/swift-ui/SlotView.d.ts +5 -2
- package/build/swift-ui/SlotView.d.ts.map +1 -1
- package/build/swift-ui/SwipeActions/index.d.ts +38 -0
- package/build/swift-ui/SwipeActions/index.d.ts.map +1 -0
- package/build/swift-ui/index.d.ts +3 -0
- package/build/swift-ui/index.d.ts.map +1 -1
- package/build/swift-ui/modifiers/index.d.ts +3 -1
- package/build/swift-ui/modifiers/index.d.ts.map +1 -1
- package/build/swift-ui/modifiers/symbolEffect.d.ts +103 -0
- package/build/swift-ui/modifiers/symbolEffect.d.ts.map +1 -0
- package/build/swift-ui/withAnimation.d.ts +26 -0
- package/build/swift-ui/withAnimation.d.ts.map +1 -0
- package/build/universal/BottomSheet/index.android.d.ts +1 -1
- package/build/universal/BottomSheet/index.android.d.ts.map +1 -1
- package/build/universal/BottomSheet/index.d.ts +1 -1
- package/build/universal/BottomSheet/index.d.ts.map +1 -1
- package/build/universal/BottomSheet/index.ios.d.ts +1 -1
- package/build/universal/BottomSheet/index.ios.d.ts.map +1 -1
- package/build/universal/BottomSheet/types.d.ts +27 -0
- package/build/universal/BottomSheet/types.d.ts.map +1 -1
- package/build/universal/Collapsible/index.android.d.ts +8 -0
- package/build/universal/Collapsible/index.android.d.ts.map +1 -0
- package/build/universal/Collapsible/index.d.ts +8 -0
- package/build/universal/Collapsible/index.d.ts.map +1 -0
- package/build/universal/Collapsible/index.ios.d.ts +7 -0
- package/build/universal/Collapsible/index.ios.d.ts.map +1 -0
- package/build/universal/Collapsible/types.d.ts +23 -0
- package/build/universal/Collapsible/types.d.ts.map +1 -0
- package/build/universal/Column/index.d.ts.map +1 -1
- package/build/universal/Host/index.d.ts +5 -7
- package/build/universal/Host/index.d.ts.map +1 -1
- package/build/universal/Host/types.d.ts +72 -0
- package/build/universal/Host/types.d.ts.map +1 -0
- package/build/universal/List/index.android.d.ts +9 -0
- package/build/universal/List/index.android.d.ts.map +1 -0
- package/build/universal/List/index.d.ts +8 -0
- package/build/universal/List/index.d.ts.map +1 -0
- package/build/universal/List/index.ios.d.ts +8 -0
- package/build/universal/List/index.ios.d.ts.map +1 -0
- package/build/universal/List/types.d.ts +26 -0
- package/build/universal/List/types.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.android.d.ts +8 -0
- package/build/universal/ListItem/ListItem.android.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.d.ts +9 -0
- package/build/universal/ListItem/ListItem.d.ts.map +1 -0
- package/build/universal/ListItem/ListItem.ios.d.ts +8 -0
- package/build/universal/ListItem/ListItem.ios.d.ts.map +1 -0
- package/build/universal/ListItem/ListItemSlots.d.ts +21 -0
- package/build/universal/ListItem/ListItemSlots.d.ts.map +1 -0
- package/build/universal/ListItem/index.d.ts +10 -0
- package/build/universal/ListItem/index.d.ts.map +1 -0
- package/build/universal/ListItem/types.d.ts +59 -0
- package/build/universal/ListItem/types.d.ts.map +1 -0
- package/build/universal/Picker/Picker.android.d.ts +9 -0
- package/build/universal/Picker/Picker.android.d.ts.map +1 -0
- package/build/universal/Picker/Picker.d.ts +8 -0
- package/build/universal/Picker/Picker.d.ts.map +1 -0
- package/build/universal/Picker/Picker.ios.d.ts +9 -0
- package/build/universal/Picker/Picker.ios.d.ts.map +1 -0
- package/build/universal/Picker/PickerItem.d.ts +9 -0
- package/build/universal/Picker/PickerItem.d.ts.map +1 -0
- package/build/universal/Picker/index.d.ts +8 -0
- package/build/universal/Picker/index.d.ts.map +1 -0
- package/build/universal/Picker/types.d.ts +69 -0
- package/build/universal/Picker/types.d.ts.map +1 -0
- package/build/universal/index.d.ts +4 -0
- package/build/universal/index.d.ts.map +1 -1
- package/expo-module.config.json +1 -1
- package/ios/Alert/Alert.swift +56 -0
- package/ios/Alert/AlertProps.swift +8 -0
- package/ios/BottomSheetView.swift +4 -1
- package/ios/ExpoUIModule.swift +43 -1
- package/ios/ExpoUITouchHandlerHelper.h +4 -1
- package/ios/ExpoUITouchHandlerHelper.mm +1 -0
- package/ios/Modifiers/AnimationConfig.swift +109 -0
- package/ios/Modifiers/SwipeActionsModifier.swift +97 -0
- package/ios/Modifiers/SymbolEffectModifier.swift +452 -0
- package/ios/Modifiers/ViewModifierRegistry.swift +5 -112
- package/ios/SlotView.swift +5 -0
- package/ios/State/ObservableState.swift +12 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7-sources.jar → 56.0.9/expo.modules.ui-56.0.9-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.module → 56.0.9/expo.modules.ui-56.0.9.module} +22 -22
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.pom → 56.0.9/expo.modules.ui-56.0.9.pom} +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.9/expo.modules.ui-56.0.9.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 +7 -3
- package/src/State/useNativeState.ts +70 -10
- package/src/community/bottom-sheet/BottomSheet.ios.tsx +0 -17
- package/src/community/menu/MenuView.android.tsx +224 -0
- package/src/community/menu/MenuView.ios.tsx +149 -0
- package/src/community/menu/MenuView.tsx +36 -0
- package/src/community/menu/index.tsx +14 -0
- package/src/community/menu/types.tsx +171 -0
- package/src/jetpack-compose/LoadingIndicator/index.tsx +92 -0
- package/src/jetpack-compose/Snackbar/index.tsx +135 -0
- package/src/jetpack-compose/index.ts +2 -0
- package/src/jetpack-compose/modifiers/index.ts +30 -2
- package/src/swift-ui/Alert/index.tsx +87 -0
- package/src/swift-ui/BottomSheet/index.tsx +32 -15
- package/src/swift-ui/SlotView.tsx +17 -4
- package/src/swift-ui/SwipeActions/index.tsx +73 -0
- package/src/swift-ui/index.tsx +3 -0
- package/src/swift-ui/modifiers/index.ts +3 -0
- package/src/swift-ui/modifiers/symbolEffect.ts +181 -0
- package/src/swift-ui/withAnimation.ts +71 -0
- package/src/ts-declarations/react-native-web.d.ts +27 -0
- package/src/universal/BottomSheet/index.android.tsx +27 -3
- package/src/universal/BottomSheet/index.ios.tsx +30 -12
- package/src/universal/BottomSheet/index.tsx +46 -4
- package/src/universal/BottomSheet/types.ts +25 -0
- package/src/universal/Collapsible/index.android.tsx +72 -0
- package/src/universal/Collapsible/index.ios.tsx +16 -0
- package/src/universal/Collapsible/index.tsx +58 -0
- package/src/universal/Collapsible/types.ts +25 -0
- package/src/universal/Column/index.tsx +3 -1
- package/src/universal/Host/index.tsx +69 -5
- package/src/universal/Host/types.ts +70 -0
- package/src/universal/List/index.android.tsx +44 -0
- package/src/universal/List/index.ios.tsx +19 -0
- package/src/universal/List/index.tsx +26 -0
- package/src/universal/List/types.ts +28 -0
- package/src/universal/ListItem/ListItem.android.tsx +52 -0
- package/src/universal/ListItem/ListItem.ios.tsx +58 -0
- package/src/universal/ListItem/ListItem.tsx +72 -0
- package/src/universal/ListItem/ListItemSlots.tsx +66 -0
- package/src/universal/ListItem/index.ts +15 -0
- package/src/universal/ListItem/types.ts +67 -0
- package/src/universal/Picker/Picker.android.tsx +69 -0
- package/src/universal/Picker/Picker.ios.tsx +45 -0
- package/src/universal/Picker/Picker.tsx +52 -0
- package/src/universal/Picker/PickerItem.tsx +27 -0
- package/src/universal/Picker/index.ts +11 -0
- package/src/universal/Picker/types.ts +79 -0
- package/src/universal/index.ts +4 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha512 +0 -1
- package/src/community/bottom-sheet/CLAUDE.md +0 -55
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright 2025-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
internal enum SwipeActionsEdge: String, Enumerable {
|
|
7
|
+
case leading
|
|
8
|
+
case trailing
|
|
9
|
+
|
|
10
|
+
func toNativeEdge() -> HorizontalEdge {
|
|
11
|
+
switch self {
|
|
12
|
+
case .leading:
|
|
13
|
+
return .leading
|
|
14
|
+
case .trailing:
|
|
15
|
+
return .trailing
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
internal final class SwipeActionsViewProps: UIBaseViewProps {
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private struct SwipeActionsSlot {
|
|
24
|
+
let edge: SwipeActionsEdge
|
|
25
|
+
let allowsFullSwipe: Bool
|
|
26
|
+
let view: SlotView
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
internal struct SwipeActionsView: ExpoSwiftUI.View {
|
|
30
|
+
@ObservedObject var props: SwipeActionsViewProps
|
|
31
|
+
|
|
32
|
+
var body: some View {
|
|
33
|
+
let child = props.children?.withoutSlots().first
|
|
34
|
+
#if os(tvOS)
|
|
35
|
+
if let child {
|
|
36
|
+
let view: any View = child.childView
|
|
37
|
+
AnyView(view)
|
|
38
|
+
}
|
|
39
|
+
#else
|
|
40
|
+
if let child {
|
|
41
|
+
let view: any View = child.childView
|
|
42
|
+
contentWithSwipeActions(AnyView(view))
|
|
43
|
+
}
|
|
44
|
+
#endif
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#if !os(tvOS)
|
|
48
|
+
@ViewBuilder
|
|
49
|
+
private func contentWithSwipeActions(_ content: AnyView) -> some View {
|
|
50
|
+
let leading = actionSlot(for: .leading)
|
|
51
|
+
let trailing = actionSlot(for: .trailing)
|
|
52
|
+
|
|
53
|
+
if let leading, let trailing {
|
|
54
|
+
content
|
|
55
|
+
.swipeActions(edge: .leading, allowsFullSwipe: leading.allowsFullSwipe) {
|
|
56
|
+
leading.view
|
|
57
|
+
}
|
|
58
|
+
.swipeActions(edge: .trailing, allowsFullSwipe: trailing.allowsFullSwipe) {
|
|
59
|
+
trailing.view
|
|
60
|
+
}
|
|
61
|
+
} else if let leading {
|
|
62
|
+
content
|
|
63
|
+
.swipeActions(edge: .leading, allowsFullSwipe: leading.allowsFullSwipe) {
|
|
64
|
+
leading.view
|
|
65
|
+
}
|
|
66
|
+
} else if let trailing {
|
|
67
|
+
content
|
|
68
|
+
.swipeActions(edge: .trailing, allowsFullSwipe: trailing.allowsFullSwipe) {
|
|
69
|
+
trailing.view
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
content
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
private func actionSlot(for edge: SwipeActionsEdge) -> SwipeActionsSlot? {
|
|
78
|
+
props.children?
|
|
79
|
+
.compactMap { $0.childView as? SlotView }
|
|
80
|
+
.compactMap(parseActionSlot)
|
|
81
|
+
.first { $0.edge == edge }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private func parseActionSlot(_ slot: SlotView) -> SwipeActionsSlot? {
|
|
85
|
+
guard slot.props.name == "actions",
|
|
86
|
+
let edgeName = slot.extra("edge", as: String.self),
|
|
87
|
+
let edge = SwipeActionsEdge(rawValue: edgeName) else {
|
|
88
|
+
return nil
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return SwipeActionsSlot(
|
|
92
|
+
edge: edge,
|
|
93
|
+
allowsFullSwipe: slot.extra("allowsFullSwipe", as: Bool.self) ?? true,
|
|
94
|
+
view: slot
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
// Copyright 2026-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
// MARK: - Effect kind
|
|
7
|
+
|
|
8
|
+
internal enum SymbolEffectKind: String, Enumerable {
|
|
9
|
+
case appear
|
|
10
|
+
case bounce
|
|
11
|
+
case breathe
|
|
12
|
+
case disappear
|
|
13
|
+
case drawOff
|
|
14
|
+
case drawOn
|
|
15
|
+
case pulse
|
|
16
|
+
case rotate
|
|
17
|
+
case scale
|
|
18
|
+
case variableColor
|
|
19
|
+
case wiggle
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// MARK: - Effect option enums
|
|
23
|
+
|
|
24
|
+
internal enum SymbolEffectScope: String, Enumerable {
|
|
25
|
+
case byLayer
|
|
26
|
+
case wholeSymbol
|
|
27
|
+
case individually
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
internal enum SymbolEffectDirection: String, Enumerable {
|
|
31
|
+
case up
|
|
32
|
+
case down
|
|
33
|
+
case left
|
|
34
|
+
case right
|
|
35
|
+
case forward
|
|
36
|
+
case backward
|
|
37
|
+
case clockwise
|
|
38
|
+
case counterClockwise
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
internal enum SymbolEffectScale: String, Enumerable {
|
|
42
|
+
case up
|
|
43
|
+
case down
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
internal enum SymbolEffectBreatheStyle: String, Enumerable {
|
|
47
|
+
case plain
|
|
48
|
+
case pulse
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
internal enum SymbolEffectFillStyle: String, Enumerable {
|
|
52
|
+
case iterative
|
|
53
|
+
case cumulative
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
internal enum SymbolEffectPlaybackStyle: String, Enumerable {
|
|
57
|
+
case reversing
|
|
58
|
+
case nonReversing
|
|
59
|
+
case reversed
|
|
60
|
+
case nonReversed
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
internal enum SymbolEffectInactiveLayers: String, Enumerable {
|
|
64
|
+
case dim
|
|
65
|
+
case hide
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// MARK: - Options config
|
|
69
|
+
|
|
70
|
+
internal enum SymbolEffectRepeatKind: String, Enumerable {
|
|
71
|
+
case continuous
|
|
72
|
+
case nonRepeating
|
|
73
|
+
case periodic
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
internal struct SymbolEffectOptionsConfig: Record {
|
|
77
|
+
@Field var repeatKind: SymbolEffectRepeatKind?
|
|
78
|
+
@Field var repeatCount: Int?
|
|
79
|
+
@Field var repeatDelay: Double?
|
|
80
|
+
@Field var speed: Double?
|
|
81
|
+
|
|
82
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
83
|
+
func toSwiftUI() -> SymbolEffectOptions {
|
|
84
|
+
var options: SymbolEffectOptions = .default
|
|
85
|
+
|
|
86
|
+
switch repeatKind {
|
|
87
|
+
case .nonRepeating:
|
|
88
|
+
options = .nonRepeating
|
|
89
|
+
case .continuous:
|
|
90
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
91
|
+
options = .repeat(.continuous)
|
|
92
|
+
}
|
|
93
|
+
// iOS 17: indefinite effects loop by default, so `.default` is fine here.
|
|
94
|
+
case .periodic:
|
|
95
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
96
|
+
options = .repeat(.periodic(repeatCount, delay: repeatDelay))
|
|
97
|
+
}
|
|
98
|
+
case .none:
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if let speed {
|
|
103
|
+
options = options.speed(speed)
|
|
104
|
+
}
|
|
105
|
+
return options
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// MARK: - Effect config
|
|
110
|
+
|
|
111
|
+
internal struct SymbolEffectConfig: Record {
|
|
112
|
+
@Field var effect: SymbolEffectKind = .pulse
|
|
113
|
+
@Field var direction: SymbolEffectDirection?
|
|
114
|
+
@Field var scale: SymbolEffectScale?
|
|
115
|
+
@Field var style: SymbolEffectBreatheStyle?
|
|
116
|
+
@Field var customAngle: Double?
|
|
117
|
+
@Field var fillStyle: SymbolEffectFillStyle?
|
|
118
|
+
@Field var playbackStyle: SymbolEffectPlaybackStyle?
|
|
119
|
+
@Field var inactiveLayers: SymbolEffectInactiveLayers?
|
|
120
|
+
@Field var scope: SymbolEffectScope?
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// MARK: - Modifier
|
|
124
|
+
|
|
125
|
+
internal struct SymbolEffectModifier: ViewModifier, Record {
|
|
126
|
+
@Field var effect: SymbolEffectConfig
|
|
127
|
+
@Field var options: SymbolEffectOptionsConfig?
|
|
128
|
+
@Field var isActive: ObservableState?
|
|
129
|
+
@Field var value: ObservableState?
|
|
130
|
+
|
|
131
|
+
@ViewBuilder
|
|
132
|
+
func body(content: Content) -> some View {
|
|
133
|
+
if #available(iOS 17.0, tvOS 17.0, *) {
|
|
134
|
+
let resolvedOptions = options?.toSwiftUI() ?? .default
|
|
135
|
+
if let value {
|
|
136
|
+
DiscreteEffectView(
|
|
137
|
+
config: effect,
|
|
138
|
+
options: resolvedOptions,
|
|
139
|
+
state: value
|
|
140
|
+
) {
|
|
141
|
+
content
|
|
142
|
+
}
|
|
143
|
+
} else if let isActive {
|
|
144
|
+
IndefiniteEffectView(
|
|
145
|
+
config: effect,
|
|
146
|
+
options: resolvedOptions,
|
|
147
|
+
state: isActive
|
|
148
|
+
) {
|
|
149
|
+
content
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
applyIndefiniteEffect(
|
|
153
|
+
to: content,
|
|
154
|
+
config: effect,
|
|
155
|
+
options: resolvedOptions,
|
|
156
|
+
isActive: true
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
content
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// MARK: - Per-effect builders
|
|
166
|
+
|
|
167
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
168
|
+
private func buildPulseEffect(_ config: SymbolEffectConfig) -> PulseSymbolEffect {
|
|
169
|
+
return switch config.scope {
|
|
170
|
+
case .byLayer: .pulse.byLayer
|
|
171
|
+
case .wholeSymbol: .pulse.wholeSymbol
|
|
172
|
+
default: .pulse
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
177
|
+
private func buildBounceEffect(_ config: SymbolEffectConfig) -> BounceSymbolEffect {
|
|
178
|
+
let directed: BounceSymbolEffect = switch config.direction {
|
|
179
|
+
case .up: .bounce.up
|
|
180
|
+
case .down: .bounce.down
|
|
181
|
+
default: .bounce
|
|
182
|
+
}
|
|
183
|
+
return switch config.scope {
|
|
184
|
+
case .byLayer: directed.byLayer
|
|
185
|
+
case .wholeSymbol: directed.wholeSymbol
|
|
186
|
+
default: directed
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
191
|
+
private func buildVariableColorEffect(_ config: SymbolEffectConfig) -> VariableColorSymbolEffect {
|
|
192
|
+
let filled: VariableColorSymbolEffect = switch config.fillStyle {
|
|
193
|
+
case .iterative: .variableColor.iterative
|
|
194
|
+
case .cumulative: .variableColor.cumulative
|
|
195
|
+
default: .variableColor
|
|
196
|
+
}
|
|
197
|
+
let playing: VariableColorSymbolEffect = switch config.playbackStyle {
|
|
198
|
+
case .reversing: filled.reversing
|
|
199
|
+
case .nonReversing: filled.nonReversing
|
|
200
|
+
default: filled
|
|
201
|
+
}
|
|
202
|
+
return switch config.inactiveLayers {
|
|
203
|
+
case .dim: playing.dimInactiveLayers
|
|
204
|
+
case .hide: playing.hideInactiveLayers
|
|
205
|
+
default: playing
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
210
|
+
private func buildScaleEffect(_ config: SymbolEffectConfig) -> ScaleSymbolEffect {
|
|
211
|
+
let scaled: ScaleSymbolEffect = switch config.scale {
|
|
212
|
+
case .up: .scale.up
|
|
213
|
+
case .down: .scale.down
|
|
214
|
+
default: .scale
|
|
215
|
+
}
|
|
216
|
+
return switch config.scope {
|
|
217
|
+
case .byLayer: scaled.byLayer
|
|
218
|
+
case .wholeSymbol: scaled.wholeSymbol
|
|
219
|
+
default: scaled
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
224
|
+
private func buildAppearEffect(_ config: SymbolEffectConfig) -> AppearSymbolEffect {
|
|
225
|
+
let scaled: AppearSymbolEffect = switch config.scale {
|
|
226
|
+
case .up: .appear.up
|
|
227
|
+
case .down: .appear.down
|
|
228
|
+
default: .appear
|
|
229
|
+
}
|
|
230
|
+
return switch config.scope {
|
|
231
|
+
case .byLayer: scaled.byLayer
|
|
232
|
+
case .wholeSymbol: scaled.wholeSymbol
|
|
233
|
+
default: scaled
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
238
|
+
private func buildDisappearEffect(_ config: SymbolEffectConfig) -> DisappearSymbolEffect {
|
|
239
|
+
let scaled: DisappearSymbolEffect = switch config.scale {
|
|
240
|
+
case .up: .disappear.up
|
|
241
|
+
case .down: .disappear.down
|
|
242
|
+
default: .disappear
|
|
243
|
+
}
|
|
244
|
+
return switch config.scope {
|
|
245
|
+
case .byLayer: scaled.byLayer
|
|
246
|
+
case .wholeSymbol: scaled.wholeSymbol
|
|
247
|
+
default: scaled
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@available(iOS 18.0, tvOS 18.0, *)
|
|
252
|
+
private func buildWiggleEffect(_ config: SymbolEffectConfig) -> WiggleSymbolEffect {
|
|
253
|
+
let directed: WiggleSymbolEffect = if let angle = config.customAngle {
|
|
254
|
+
.wiggle.custom(angle: angle)
|
|
255
|
+
} else {
|
|
256
|
+
switch config.direction {
|
|
257
|
+
case .up: .wiggle.up
|
|
258
|
+
case .down: .wiggle.down
|
|
259
|
+
case .left: .wiggle.left
|
|
260
|
+
case .right: .wiggle.right
|
|
261
|
+
case .forward: .wiggle.forward
|
|
262
|
+
case .backward: .wiggle.backward
|
|
263
|
+
case .clockwise: .wiggle.clockwise
|
|
264
|
+
case .counterClockwise: .wiggle.counterClockwise
|
|
265
|
+
default: .wiggle
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return switch config.scope {
|
|
269
|
+
case .byLayer: directed.byLayer
|
|
270
|
+
case .wholeSymbol: directed.wholeSymbol
|
|
271
|
+
default: directed
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@available(iOS 18.0, tvOS 18.0, *)
|
|
276
|
+
private func buildBreatheEffect(_ config: SymbolEffectConfig) -> BreatheSymbolEffect {
|
|
277
|
+
let styled: BreatheSymbolEffect = switch config.style {
|
|
278
|
+
case .pulse: .breathe.pulse
|
|
279
|
+
case .plain: .breathe.plain
|
|
280
|
+
default: .breathe
|
|
281
|
+
}
|
|
282
|
+
return switch config.scope {
|
|
283
|
+
case .byLayer: styled.byLayer
|
|
284
|
+
case .wholeSymbol: styled.wholeSymbol
|
|
285
|
+
default: styled
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
@available(iOS 18.0, tvOS 18.0, *)
|
|
290
|
+
private func buildRotateEffect(_ config: SymbolEffectConfig) -> RotateSymbolEffect {
|
|
291
|
+
let directed: RotateSymbolEffect = switch config.direction {
|
|
292
|
+
case .clockwise: .rotate.clockwise
|
|
293
|
+
case .counterClockwise: .rotate.counterClockwise
|
|
294
|
+
default: .rotate
|
|
295
|
+
}
|
|
296
|
+
return switch config.scope {
|
|
297
|
+
case .byLayer: directed.byLayer
|
|
298
|
+
case .wholeSymbol: directed.wholeSymbol
|
|
299
|
+
default: directed
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@available(iOS 26.0, tvOS 26.0, *)
|
|
304
|
+
private func buildDrawOnEffect(_ config: SymbolEffectConfig) -> DrawOnSymbolEffect {
|
|
305
|
+
return switch config.scope {
|
|
306
|
+
case .byLayer: .drawOn.byLayer
|
|
307
|
+
case .individually: .drawOn.individually
|
|
308
|
+
case .wholeSymbol: .drawOn.wholeSymbol
|
|
309
|
+
default: .drawOn
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@available(iOS 26.0, tvOS 26.0, *)
|
|
314
|
+
private func buildDrawOffEffect(_ config: SymbolEffectConfig) -> DrawOffSymbolEffect {
|
|
315
|
+
let played: DrawOffSymbolEffect = switch config.playbackStyle {
|
|
316
|
+
case .reversed: .drawOff.reversed
|
|
317
|
+
case .nonReversed: .drawOff.nonReversed
|
|
318
|
+
default: .drawOff
|
|
319
|
+
}
|
|
320
|
+
return switch config.scope {
|
|
321
|
+
case .byLayer: played.byLayer
|
|
322
|
+
case .individually: played.individually
|
|
323
|
+
case .wholeSymbol: played.wholeSymbol
|
|
324
|
+
default: played
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// MARK: - Dispatch
|
|
329
|
+
|
|
330
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
331
|
+
@ViewBuilder
|
|
332
|
+
private func applyIndefiniteEffect<TargetView: View>(
|
|
333
|
+
to view: TargetView,
|
|
334
|
+
config: SymbolEffectConfig,
|
|
335
|
+
options: SymbolEffectOptions,
|
|
336
|
+
isActive: Bool
|
|
337
|
+
) -> some View {
|
|
338
|
+
switch config.effect {
|
|
339
|
+
case .pulse:
|
|
340
|
+
view.symbolEffect(buildPulseEffect(config), options: options, isActive: isActive)
|
|
341
|
+
case .bounce:
|
|
342
|
+
view.symbolEffect(buildBounceEffect(config), options: options, isActive: isActive)
|
|
343
|
+
case .variableColor:
|
|
344
|
+
view.symbolEffect(buildVariableColorEffect(config), options: options, isActive: isActive)
|
|
345
|
+
case .scale:
|
|
346
|
+
view.symbolEffect(buildScaleEffect(config), options: options, isActive: isActive)
|
|
347
|
+
case .appear:
|
|
348
|
+
view.symbolEffect(buildAppearEffect(config), options: options, isActive: isActive)
|
|
349
|
+
case .disappear:
|
|
350
|
+
view.symbolEffect(buildDisappearEffect(config), options: options, isActive: isActive)
|
|
351
|
+
case .wiggle:
|
|
352
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
353
|
+
view.symbolEffect(buildWiggleEffect(config), options: options, isActive: isActive)
|
|
354
|
+
} else {
|
|
355
|
+
view
|
|
356
|
+
}
|
|
357
|
+
case .breathe:
|
|
358
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
359
|
+
view.symbolEffect(buildBreatheEffect(config), options: options, isActive: isActive)
|
|
360
|
+
} else {
|
|
361
|
+
view
|
|
362
|
+
}
|
|
363
|
+
case .rotate:
|
|
364
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
365
|
+
view.symbolEffect(buildRotateEffect(config), options: options, isActive: isActive)
|
|
366
|
+
} else {
|
|
367
|
+
view
|
|
368
|
+
}
|
|
369
|
+
case .drawOn:
|
|
370
|
+
if #available(iOS 26.0, tvOS 26.0, *) {
|
|
371
|
+
view.symbolEffect(buildDrawOnEffect(config), options: options, isActive: isActive)
|
|
372
|
+
} else {
|
|
373
|
+
view
|
|
374
|
+
}
|
|
375
|
+
case .drawOff:
|
|
376
|
+
if #available(iOS 26.0, tvOS 26.0, *) {
|
|
377
|
+
view.symbolEffect(buildDrawOffEffect(config), options: options, isActive: isActive)
|
|
378
|
+
} else {
|
|
379
|
+
view
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
385
|
+
@ViewBuilder
|
|
386
|
+
private func applyDiscreteEffect<TargetView: View>(
|
|
387
|
+
to view: TargetView,
|
|
388
|
+
config: SymbolEffectConfig,
|
|
389
|
+
options: SymbolEffectOptions,
|
|
390
|
+
value: AnyHashable
|
|
391
|
+
) -> some View {
|
|
392
|
+
switch config.effect {
|
|
393
|
+
case .pulse:
|
|
394
|
+
view.symbolEffect(buildPulseEffect(config), options: options, value: value)
|
|
395
|
+
case .bounce:
|
|
396
|
+
view.symbolEffect(buildBounceEffect(config), options: options, value: value)
|
|
397
|
+
case .variableColor:
|
|
398
|
+
view.symbolEffect(buildVariableColorEffect(config), options: options, value: value)
|
|
399
|
+
case .wiggle:
|
|
400
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
401
|
+
view.symbolEffect(buildWiggleEffect(config), options: options, value: value)
|
|
402
|
+
} else {
|
|
403
|
+
view
|
|
404
|
+
}
|
|
405
|
+
case .breathe:
|
|
406
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
407
|
+
view.symbolEffect(buildBreatheEffect(config), options: options, value: value)
|
|
408
|
+
} else {
|
|
409
|
+
view
|
|
410
|
+
}
|
|
411
|
+
case .rotate:
|
|
412
|
+
if #available(iOS 18.0, tvOS 18.0, *) {
|
|
413
|
+
view.symbolEffect(buildRotateEffect(config), options: options, value: value)
|
|
414
|
+
} else {
|
|
415
|
+
view
|
|
416
|
+
}
|
|
417
|
+
// Scale, Appear, Disappear, DrawOn, DrawOff don't conform to
|
|
418
|
+
// DiscreteSymbolEffect — they no-op when bound to a `value`.
|
|
419
|
+
case .scale, .appear, .disappear, .drawOn, .drawOff:
|
|
420
|
+
view
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// MARK: - Discrete wrapper
|
|
425
|
+
|
|
426
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
427
|
+
private struct DiscreteEffectView<WrappedContent: View>: View {
|
|
428
|
+
let config: SymbolEffectConfig
|
|
429
|
+
let options: SymbolEffectOptions
|
|
430
|
+
@ObservedObject var state: ObservableState
|
|
431
|
+
@ViewBuilder let content: () -> WrappedContent
|
|
432
|
+
|
|
433
|
+
var body: some View {
|
|
434
|
+
let trigger = (state.value as? AnyHashable) ?? AnyHashable(0)
|
|
435
|
+
applyDiscreteEffect(to: content(), config: config, options: options, value: trigger)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// MARK: - Indefinite wrapper
|
|
440
|
+
|
|
441
|
+
@available(iOS 17.0, tvOS 17.0, *)
|
|
442
|
+
private struct IndefiniteEffectView<WrappedContent: View>: View {
|
|
443
|
+
let config: SymbolEffectConfig
|
|
444
|
+
let options: SymbolEffectOptions
|
|
445
|
+
@ObservedObject var state: ObservableState
|
|
446
|
+
@ViewBuilder let content: () -> WrappedContent
|
|
447
|
+
|
|
448
|
+
var body: some View {
|
|
449
|
+
let active = (state.value as? Bool) ?? true
|
|
450
|
+
applyIndefiniteEffect(to: content(), config: config, options: options, isActive: active)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
@@ -621,38 +621,12 @@ internal struct AnyViewModifier: ViewModifier {
|
|
|
621
621
|
}
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
-
internal enum AnimationType: String, Enumerable {
|
|
625
|
-
case easeInOut
|
|
626
|
-
case easeIn
|
|
627
|
-
case easeOut
|
|
628
|
-
case linear
|
|
629
|
-
case spring
|
|
630
|
-
case interpolatingSpring
|
|
631
|
-
case `default`
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
internal struct AnimationConfig: Record {
|
|
635
|
-
@Field var type: AnimationType = .default
|
|
636
|
-
@Field var duration: Double?
|
|
637
|
-
@Field var response: Double?
|
|
638
|
-
@Field var dampingFraction: Double?
|
|
639
|
-
@Field var blendDuration: Double?
|
|
640
|
-
@Field var bounce: Double?
|
|
641
|
-
@Field var mass: Double?
|
|
642
|
-
@Field var stiffness: Double?
|
|
643
|
-
@Field var damping: Double?
|
|
644
|
-
@Field var initialVelocity: Double?
|
|
645
|
-
@Field var delay: Double?
|
|
646
|
-
@Field var repeatCount: Int?
|
|
647
|
-
@Field var autoreverses: Bool?
|
|
648
|
-
}
|
|
649
|
-
|
|
650
624
|
internal struct AnimationModifier: ViewModifier, Record {
|
|
651
625
|
@Field var animation: AnimationConfig
|
|
652
626
|
@Field var animatedValue: Either<Double, Bool>?
|
|
653
627
|
|
|
654
628
|
func body(content: Content) -> some View {
|
|
655
|
-
let animationValue =
|
|
629
|
+
let animationValue = animation.toSwiftUIAnimation()
|
|
656
630
|
if let value: Bool = animatedValue?.get() {
|
|
657
631
|
content.animation(animationValue, value: value)
|
|
658
632
|
} else if let value: Double = animatedValue?.get() {
|
|
@@ -661,91 +635,6 @@ internal struct AnimationModifier: ViewModifier, Record {
|
|
|
661
635
|
content
|
|
662
636
|
}
|
|
663
637
|
}
|
|
664
|
-
|
|
665
|
-
private func parseAnimation(_ config: AnimationConfig) -> Animation {
|
|
666
|
-
let type = config.type
|
|
667
|
-
|
|
668
|
-
var animation: Animation
|
|
669
|
-
|
|
670
|
-
switch type {
|
|
671
|
-
case .easeIn:
|
|
672
|
-
if let duration = config.duration {
|
|
673
|
-
animation = .easeIn(duration: duration)
|
|
674
|
-
} else {
|
|
675
|
-
animation = .easeIn
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
case .easeOut:
|
|
679
|
-
if let duration = config.duration {
|
|
680
|
-
animation = .easeOut(duration: duration)
|
|
681
|
-
} else {
|
|
682
|
-
animation = .easeOut
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
case .linear:
|
|
686
|
-
if let duration = config.duration {
|
|
687
|
-
animation = .linear(duration: duration)
|
|
688
|
-
} else {
|
|
689
|
-
animation = .linear
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
case .easeInOut:
|
|
693
|
-
if let duration = config.duration {
|
|
694
|
-
animation = .easeInOut(duration: duration)
|
|
695
|
-
} else {
|
|
696
|
-
animation = .easeInOut
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
case .spring:
|
|
700
|
-
let duration = config.duration
|
|
701
|
-
let bounce = config.bounce
|
|
702
|
-
let response = config.response
|
|
703
|
-
let dampingFraction = config.dampingFraction
|
|
704
|
-
let blendDuration = config.blendDuration
|
|
705
|
-
|
|
706
|
-
if response != nil || dampingFraction != nil {
|
|
707
|
-
// default values are 0.5, 0.825, 0.0
|
|
708
|
-
animation = .spring(response: response ?? 0.5, dampingFraction: dampingFraction ?? 0.825, blendDuration: blendDuration ?? 0.0)
|
|
709
|
-
} else if duration != nil || bounce != nil {
|
|
710
|
-
// default values are 0.5, 0.0, 0.0
|
|
711
|
-
animation = .spring(duration: duration ?? 0.5, bounce: bounce ?? 0.0, blendDuration: blendDuration ?? 0.0)
|
|
712
|
-
} else if let blendDuration = blendDuration {
|
|
713
|
-
animation = .spring(blendDuration: blendDuration)
|
|
714
|
-
} else {
|
|
715
|
-
animation = .spring
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
case .interpolatingSpring:
|
|
719
|
-
let duration = config.duration
|
|
720
|
-
let bounce = config.bounce
|
|
721
|
-
let mass = config.mass
|
|
722
|
-
let stiffness = config.stiffness
|
|
723
|
-
let damping = config.damping
|
|
724
|
-
let initialVelocity = config.initialVelocity
|
|
725
|
-
|
|
726
|
-
if duration != nil || bounce != nil {
|
|
727
|
-
animation = .interpolatingSpring(duration: duration ?? 0.5, bounce: bounce ?? 0.0, initialVelocity: initialVelocity ?? 0.0)
|
|
728
|
-
} else if let stiffness, let damping {
|
|
729
|
-
animation = .interpolatingSpring(mass: mass ?? 1.0, stiffness: stiffness, damping: damping, initialVelocity: initialVelocity ?? 0.0)
|
|
730
|
-
} else {
|
|
731
|
-
animation = .interpolatingSpring
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
default:
|
|
735
|
-
animation = .default
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
if let delay = config.delay {
|
|
739
|
-
animation = animation.delay(delay)
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
if let repeatCount = config.repeatCount {
|
|
743
|
-
let autoreverses = config.autoreverses ?? false
|
|
744
|
-
animation = animation.repeatCount(repeatCount, autoreverses: autoreverses)
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
return animation
|
|
748
|
-
}
|
|
749
638
|
}
|
|
750
639
|
|
|
751
640
|
internal enum ScrollContentBackgroundTypes: String, Enumerable {
|
|
@@ -1957,5 +1846,9 @@ extension ViewModifierRegistry {
|
|
|
1957
1846
|
register("containerBackground") { params, appContext, _ in
|
|
1958
1847
|
return try ContainerBackgroundModifier(from: params, appContext: appContext)
|
|
1959
1848
|
}
|
|
1849
|
+
|
|
1850
|
+
register("symbolEffect") { params, appContext, _ in
|
|
1851
|
+
return try SymbolEffectModifier(from: params, appContext: appContext)
|
|
1852
|
+
}
|
|
1960
1853
|
}
|
|
1961
1854
|
}
|
package/ios/SlotView.swift
CHANGED
|
@@ -5,6 +5,7 @@ import ExpoModulesCore
|
|
|
5
5
|
|
|
6
6
|
internal final class SlotViewProps: ExpoSwiftUI.ViewProps {
|
|
7
7
|
@Field var name: String = ""
|
|
8
|
+
@Field var extraProps: [String: Any]?
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
internal struct SlotView: ExpoSwiftUI.View {
|
|
@@ -17,6 +18,10 @@ internal struct SlotView: ExpoSwiftUI.View {
|
|
|
17
18
|
var body: some View {
|
|
18
19
|
Children()
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
func extra<T>(_ key: String, as type: T.Type = T.self) -> T? {
|
|
23
|
+
return props.extraProps?[key] as? T
|
|
24
|
+
}
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
extension [any ExpoSwiftUI.AnyChild] {
|