@expo/ui 56.0.7 → 56.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +6 -2
  4. package/android/src/main/java/expo/modules/ui/HostView.kt +2 -0
  5. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +19 -1
  6. package/android/src/main/java/expo/modules/ui/RNHostView.kt +8 -3
  7. package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +28 -0
  8. package/build/community/menu/MenuView.android.d.ts +16 -0
  9. package/build/community/menu/MenuView.android.d.ts.map +1 -0
  10. package/build/community/menu/MenuView.d.ts +19 -0
  11. package/build/community/menu/MenuView.d.ts.map +1 -0
  12. package/build/community/menu/MenuView.ios.d.ts +10 -0
  13. package/build/community/menu/MenuView.ios.d.ts.map +1 -0
  14. package/build/community/menu/index.d.ts +5 -0
  15. package/build/community/menu/index.d.ts.map +1 -0
  16. package/build/community/menu/types.d.ts +166 -0
  17. package/build/community/menu/types.d.ts.map +1 -0
  18. package/build/jetpack-compose/modifiers/index.d.ts +15 -0
  19. package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
  20. package/build/swift-ui/Alert/index.d.ts +42 -0
  21. package/build/swift-ui/Alert/index.d.ts.map +1 -0
  22. package/build/swift-ui/SlotView.d.ts +5 -2
  23. package/build/swift-ui/SlotView.d.ts.map +1 -1
  24. package/build/swift-ui/SwipeActions/index.d.ts +38 -0
  25. package/build/swift-ui/SwipeActions/index.d.ts.map +1 -0
  26. package/build/swift-ui/index.d.ts +2 -0
  27. package/build/swift-ui/index.d.ts.map +1 -1
  28. package/build/swift-ui/modifiers/index.d.ts +3 -1
  29. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  30. package/build/swift-ui/modifiers/symbolEffect.d.ts +103 -0
  31. package/build/swift-ui/modifiers/symbolEffect.d.ts.map +1 -0
  32. package/build/universal/Host/index.d.ts +17 -6
  33. package/build/universal/Host/index.d.ts.map +1 -1
  34. package/expo-module.config.json +1 -1
  35. package/ios/Alert/Alert.swift +56 -0
  36. package/ios/Alert/AlertProps.swift +8 -0
  37. package/ios/ExpoUIModule.swift +2 -0
  38. package/ios/ExpoUITouchHandlerHelper.h +4 -1
  39. package/ios/ExpoUITouchHandlerHelper.mm +1 -0
  40. package/ios/Modifiers/SwipeActionsModifier.swift +97 -0
  41. package/ios/Modifiers/SymbolEffectModifier.swift +452 -0
  42. package/ios/Modifiers/ViewModifierRegistry.swift +4 -0
  43. package/ios/SlotView.swift +5 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7-sources.jar → 56.0.8/expo.modules.ui-56.0.8-sources.jar} +0 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8-sources.jar.md5 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8-sources.jar.sha1 +1 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8-sources.jar.sha256 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8-sources.jar.sha512 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.aar +0 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.aar.md5 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.aar.sha1 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.aar.sha256 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.aar.sha512 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.module → 56.0.8/expo.modules.ui-56.0.8.module} +22 -22
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.module.md5 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.module.sha1 +1 -0
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.module.sha256 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.module.sha512 +1 -0
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.7/expo.modules.ui-56.0.7.pom → 56.0.8/expo.modules.ui-56.0.8.pom} +1 -1
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.pom.md5 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.pom.sha1 +1 -0
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.pom.sha256 +1 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.8/expo.modules.ui-56.0.8.pom.sha512 +1 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  69. package/package.json +7 -3
  70. package/src/community/menu/MenuView.android.tsx +224 -0
  71. package/src/community/menu/MenuView.ios.tsx +149 -0
  72. package/src/community/menu/MenuView.tsx +36 -0
  73. package/src/community/menu/index.tsx +14 -0
  74. package/src/community/menu/types.tsx +171 -0
  75. package/src/jetpack-compose/modifiers/index.ts +25 -0
  76. package/src/swift-ui/Alert/index.tsx +87 -0
  77. package/src/swift-ui/SlotView.tsx +17 -4
  78. package/src/swift-ui/SwipeActions/index.tsx +73 -0
  79. package/src/swift-ui/index.tsx +2 -0
  80. package/src/swift-ui/modifiers/index.ts +3 -0
  81. package/src/swift-ui/modifiers/symbolEffect.ts +181 -0
  82. package/src/ts-declarations/react-native-web.d.ts +20 -0
  83. package/src/universal/Host/index.tsx +70 -5
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.md5 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha1 +0 -1
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha256 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7-sources.jar.sha512 +0 -1
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar +0 -0
  89. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.md5 +0 -1
  90. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha1 +0 -1
  91. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha256 +0 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.aar.sha512 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.md5 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha1 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha256 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.module.sha512 +0 -1
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.md5 +0 -1
  98. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha1 +0 -1
  99. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha256 +0 -1
  100. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.7/expo.modules.ui-56.0.7.pom.sha512 +0 -1
@@ -0,0 +1,87 @@
1
+ import { requireNativeView } from 'expo';
2
+ import type { NativeSyntheticEvent } from 'react-native';
3
+
4
+ import { Slot } from '../SlotView';
5
+ import { createViewModifierEventListener } from '../modifiers/utils';
6
+ import { type CommonViewModifierProps } from '../types';
7
+
8
+ /**
9
+ * Props of the `Alert` component.
10
+ */
11
+ export type AlertProps = {
12
+ /**
13
+ * The contents of the alert.
14
+ * Should include `Alert.Trigger`, `Alert.Actions`, and optionally `Alert.Message`.
15
+ */
16
+ children: React.ReactNode;
17
+ /**
18
+ * The title of the alert.
19
+ */
20
+ title: string;
21
+ /**
22
+ * Whether the alert is presented.
23
+ */
24
+ isPresented?: boolean;
25
+ /**
26
+ * A callback that is called when the `isPresented` state changes.
27
+ */
28
+ onIsPresentedChange?: (isPresented: boolean) => void;
29
+ } & CommonViewModifierProps;
30
+
31
+ type NativeAlertProps = Omit<AlertProps, 'onIsPresentedChange'> & {
32
+ onIsPresentedChange?: (event: NativeSyntheticEvent<{ isPresented: boolean }>) => void;
33
+ };
34
+
35
+ const AlertNativeView: React.ComponentType<NativeAlertProps> = requireNativeView(
36
+ 'ExpoUI',
37
+ 'AlertView'
38
+ );
39
+
40
+ /**
41
+ * The component visible all the time that triggers the alert presentation.
42
+ */
43
+ function Trigger(props: { children: React.ReactNode }) {
44
+ return <Slot name="trigger">{props.children}</Slot>;
45
+ }
46
+
47
+ /**
48
+ * The action buttons displayed in the alert. Use `Button` components from `@expo/ui/swift-ui` as children.
49
+ */
50
+ function Actions(props: { children: React.ReactNode }) {
51
+ return <Slot name="actions">{props.children}</Slot>;
52
+ }
53
+
54
+ /**
55
+ * An optional message displayed below the title in the alert.
56
+ */
57
+ function Message(props: { children: React.ReactNode }) {
58
+ return <Slot name="message">{props.children}</Slot>;
59
+ }
60
+
61
+ /**
62
+ * `Alert` presents a SwiftUI alert with a title, optional message, and action buttons.
63
+ *
64
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/alert(_:ispresented:actions:message:)).
65
+ */
66
+ function Alert(props: AlertProps) {
67
+ const { onIsPresentedChange, modifiers, children, ...restProps } = props;
68
+
69
+ const handleIsPresentedChange = (event: NativeSyntheticEvent<{ isPresented: boolean }>) => {
70
+ onIsPresentedChange?.(event.nativeEvent.isPresented);
71
+ };
72
+
73
+ return (
74
+ <AlertNativeView
75
+ {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
76
+ {...restProps}
77
+ onIsPresentedChange={handleIsPresentedChange}>
78
+ {children}
79
+ </AlertNativeView>
80
+ );
81
+ }
82
+
83
+ Alert.Trigger = Trigger;
84
+ Alert.Actions = Actions;
85
+ Alert.Message = Message;
86
+
87
+ export { Alert };
@@ -1,8 +1,21 @@
1
1
  import { requireNativeView } from 'expo';
2
2
 
3
- const SlotNativeView: React.ComponentType<{ name: string; children?: React.ReactNode }> =
4
- requireNativeView('ExpoUI', 'SlotView');
3
+ type SlotProps<ExtraProps extends Record<string, unknown> = Record<string, unknown>> = {
4
+ name: string;
5
+ extraProps?: ExtraProps;
6
+ children?: React.ReactNode;
7
+ };
5
8
 
6
- export function Slot({ name, children }: { name: string; children?: React.ReactNode }) {
7
- return <SlotNativeView name={name}>{children}</SlotNativeView>;
9
+ const SlotNativeView: React.ComponentType<SlotProps> = requireNativeView('ExpoUI', 'SlotView');
10
+
11
+ export function Slot<ExtraProps extends Record<string, unknown> = Record<string, unknown>>({
12
+ name,
13
+ extraProps,
14
+ children,
15
+ }: SlotProps<ExtraProps>) {
16
+ return (
17
+ <SlotNativeView name={name} extraProps={extraProps}>
18
+ {children}
19
+ </SlotNativeView>
20
+ );
8
21
  }
@@ -0,0 +1,73 @@
1
+ import { requireNativeView } from 'expo';
2
+
3
+ import { Slot } from '../SlotView';
4
+ import { createViewModifierEventListener } from '../modifiers/utils';
5
+ import { type CommonViewModifierProps } from '../types';
6
+
7
+ export type SwipeActionsEdge = 'leading' | 'trailing';
8
+
9
+ export type SwipeActionsProps = {
10
+ /**
11
+ * The regular content and `SwipeActions.Actions` action groups.
12
+ */
13
+ children: React.ReactNode;
14
+ } & CommonViewModifierProps;
15
+
16
+ export type SwipeActionsGroupProps = {
17
+ /**
18
+ * The edge where these swipe actions are revealed.
19
+ * @default 'trailing'
20
+ */
21
+ edge?: SwipeActionsEdge;
22
+ /**
23
+ * Whether a full swipe automatically performs the first action in this group.
24
+ * @default true
25
+ */
26
+ allowsFullSwipe?: boolean;
27
+ /**
28
+ * The buttons revealed when the user swipes from this edge.
29
+ */
30
+ children: React.ReactNode;
31
+ };
32
+
33
+ type SwipeActionsNativeProps = SwipeActionsProps;
34
+
35
+ const SwipeActionsNativeView: React.ComponentType<SwipeActionsNativeProps> = requireNativeView(
36
+ 'ExpoUI',
37
+ 'SwipeActionsView'
38
+ );
39
+
40
+ /**
41
+ * The buttons revealed when the user swipes the regular content from an edge.
42
+ */
43
+ export function Actions({
44
+ edge = 'trailing',
45
+ allowsFullSwipe = true,
46
+ children,
47
+ }: SwipeActionsGroupProps) {
48
+ return (
49
+ <Slot name="actions" extraProps={{ edge, allowsFullSwipe }}>
50
+ {children}
51
+ </Slot>
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Applies native SwiftUI swipe actions to its non-slot children.
57
+ * @platform ios
58
+ */
59
+ function SwipeActionsComponent(props: SwipeActionsProps) {
60
+ const { modifiers, ...restProps } = props;
61
+
62
+ return (
63
+ <SwipeActionsNativeView
64
+ modifiers={modifiers}
65
+ {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
66
+ {...restProps}
67
+ />
68
+ );
69
+ }
70
+
71
+ const SwipeActions = Object.assign(SwipeActionsComponent, { Actions });
72
+
73
+ export { SwipeActions };
@@ -1,6 +1,7 @@
1
1
  import '../State/index.fx';
2
2
 
3
3
  export * from './AccessoryWidgetBackground';
4
+ export * from './Alert';
4
5
  export * from './BottomSheet';
5
6
  export * from './Button';
6
7
  export * from './Chart';
@@ -33,6 +34,7 @@ export * from './ShareLink';
33
34
  export * from './Slider';
34
35
  export * from './Spacer';
35
36
  export * from './Stepper';
37
+ export * from './SwipeActions';
36
38
  export * from './Text';
37
39
  export { useNativeState } from '../State/useNativeState';
38
40
  export * from './SyncToggle';
@@ -20,6 +20,7 @@ import { environment } from './environment';
20
20
  import { gaugeStyle } from './gaugeStyle';
21
21
  import { progressViewStyle } from './progressViewStyle';
22
22
  import { id, scrollPosition } from './scrollPosition';
23
+ import { symbolEffect } from './symbolEffect';
23
24
  import type { Color } from './types';
24
25
  import { widgetAccentedRenderingMode, widgetURL } from './widgets';
25
26
 
@@ -1376,6 +1377,7 @@ export type BuiltInModifier =
1376
1377
  | ReturnType<typeof listStyle>
1377
1378
  | ReturnType<typeof contentTransition>
1378
1379
  | ReturnType<typeof resizable>
1380
+ | ReturnType<typeof symbolEffect>
1379
1381
  | ReturnType<typeof widgetAccentedRenderingMode>
1380
1382
  | ReturnType<typeof widgetURL>
1381
1383
  | ReturnType<typeof containerBackground>;
@@ -1426,6 +1428,7 @@ export * from './gaugeStyle';
1426
1428
  export * from './presentationModifiers';
1427
1429
  export * from './environment';
1428
1430
  export * from './scrollPosition';
1431
+ export * from './symbolEffect';
1429
1432
  export * from './widgets';
1430
1433
  export type {
1431
1434
  TimingAnimationParams,
@@ -0,0 +1,181 @@
1
+ import { createModifier } from './createModifier';
2
+ import { type ObservableState } from '../../State/useNativeState';
3
+ import { getStateId } from '../../State/utils';
4
+
5
+ // https://developer.apple.com/documentation/symbols/appearsymboleffect
6
+ type AppearSymbolEffect = {
7
+ effect: 'appear';
8
+ scale?: 'down' | 'up';
9
+ scope?: 'byLayer' | 'wholeSymbol';
10
+ };
11
+
12
+ // https://developer.apple.com/documentation/symbols/bouncesymboleffect
13
+ type BounceSymbolEffect = {
14
+ effect: 'bounce';
15
+ direction?: 'down' | 'up';
16
+ scope?: 'byLayer' | 'wholeSymbol';
17
+ };
18
+
19
+ // https://developer.apple.com/documentation/symbols/breathesymboleffect
20
+ type BreatheSymbolEffect = {
21
+ effect: 'breathe';
22
+ style?: 'plain' | 'pulse';
23
+ scope?: 'byLayer' | 'wholeSymbol';
24
+ };
25
+
26
+ // https://developer.apple.com/documentation/symbols/disappearsymboleffect
27
+ type DisappearSymbolEffect = {
28
+ effect: 'disappear';
29
+ scale?: 'down' | 'up';
30
+ scope?: 'byLayer' | 'wholeSymbol';
31
+ };
32
+
33
+ // https://developer.apple.com/documentation/symbols/drawoffsymboleffect
34
+ type DrawOffSymbolEffect = {
35
+ effect: 'drawOff';
36
+ playbackStyle?: 'nonReversed' | 'reversed';
37
+ scope?: 'byLayer' | 'individually' | 'wholeSymbol';
38
+ };
39
+
40
+ // https://developer.apple.com/documentation/symbols/drawonsymboleffect
41
+ type DrawOnSymbolEffect = {
42
+ effect: 'drawOn';
43
+ scope?: 'byLayer' | 'individually' | 'wholeSymbol';
44
+ };
45
+
46
+ // https://developer.apple.com/documentation/symbols/pulsesymboleffect
47
+ type PulseSymbolEffect = {
48
+ effect: 'pulse';
49
+ scope?: 'byLayer' | 'wholeSymbol';
50
+ };
51
+
52
+ // https://developer.apple.com/documentation/symbols/rotatesymboleffect
53
+ type RotateSymbolEffect = {
54
+ effect: 'rotate';
55
+ direction?: 'clockwise' | 'counterClockwise';
56
+ scope?: 'byLayer' | 'wholeSymbol';
57
+ };
58
+
59
+ // https://developer.apple.com/documentation/symbols/scalesymboleffect
60
+ type ScaleSymbolEffect = {
61
+ effect: 'scale';
62
+ scale?: 'down' | 'up';
63
+ scope?: 'byLayer' | 'wholeSymbol';
64
+ };
65
+
66
+ // https://developer.apple.com/documentation/symbols/variablecolorsymboleffect
67
+ type VariableColorSymbolEffect = {
68
+ effect: 'variableColor';
69
+ fillStyle?: 'cumulative' | 'iterative';
70
+ playbackStyle?: 'nonReversing' | 'reversing';
71
+ inactiveLayers?: 'dim' | 'hide';
72
+ };
73
+
74
+ // https://developer.apple.com/documentation/symbols/wigglesymboleffect
75
+ type WiggleSymbolEffect = {
76
+ effect: 'wiggle';
77
+ direction?:
78
+ | 'backward'
79
+ | 'clockwise'
80
+ | 'counterClockwise'
81
+ | 'down'
82
+ | 'forward'
83
+ | 'left'
84
+ | 'right'
85
+ | 'up';
86
+ // Custom wiggle angle in degrees. Takes precedence over `direction` when set.
87
+ customAngle?: number;
88
+ scope?: 'byLayer' | 'wholeSymbol';
89
+ };
90
+
91
+ export type SymbolEffect =
92
+ | AppearSymbolEffect
93
+ | BounceSymbolEffect
94
+ | BreatheSymbolEffect
95
+ | DisappearSymbolEffect
96
+ | DrawOffSymbolEffect
97
+ | DrawOnSymbolEffect
98
+ | PulseSymbolEffect
99
+ | RotateSymbolEffect
100
+ | ScaleSymbolEffect
101
+ | VariableColorSymbolEffect
102
+ | WiggleSymbolEffect;
103
+
104
+ /**
105
+ * Animation options for a symbol effect.
106
+ *
107
+ * @see Official [Apple documentation](https://developer.apple.com/documentation/symbols/symboleffectoptions).
108
+ */
109
+ export type SymbolEffectOptions = {
110
+ /**
111
+ * How the effect repeats. Omit for the effect's natural cadence.
112
+ * - `'nonRepeating'` — play exactly once.
113
+ * - `'continuous'` — smooth, indefinite repetition (iOS 18+).
114
+ * - `{ count?, delay? }` — periodic repetition with optional count and delay in seconds (iOS 18+).
115
+ */
116
+ repeat?: 'continuous' | 'nonRepeating' | { count?: number; delay?: number };
117
+ /** Animation speed multiplier (1.0 = default). */
118
+ speed?: number;
119
+ };
120
+
121
+ /** Equatable primitive accepted as a discrete effect trigger. */
122
+ export type DiscreteSymbolEffectValue = number | string | boolean;
123
+
124
+ /**
125
+ * Applies an SF Symbol effect to a view.
126
+ *
127
+ * @platform ios 17.0+
128
+ * @platform tvos 17.0+
129
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/symbolEffect(_:options:value:)).
130
+ *
131
+ * @example
132
+ * ```tsx
133
+ * const trigger = useNativeState(0);
134
+ * <Image
135
+ * systemName="bell.fill"
136
+ * modifiers={[symbolEffect({ effect: 'bounce', direction: 'up' }, { value: trigger })]}
137
+ * />
138
+ * ```
139
+ */
140
+ export const symbolEffect = (
141
+ effect: SymbolEffect,
142
+ args: {
143
+ options?: SymbolEffectOptions;
144
+ /** Indefinite effects: runs while `state.value === true`. Default active when omitted. */
145
+ isActive?: ObservableState<boolean>;
146
+ /** Discrete effects: the effect fires once each time this value changes. */
147
+ value?: ObservableState<DiscreteSymbolEffectValue>;
148
+ } = {}
149
+ ) => {
150
+ const { options, isActive, value } = args;
151
+ return createModifier('symbolEffect', {
152
+ effect,
153
+ options: flattenOptions(options),
154
+ isActive: isActive ? getStateId(isActive) : undefined,
155
+ value: value ? getStateId(value) : undefined,
156
+ });
157
+ };
158
+
159
+ function flattenOptions(options?: SymbolEffectOptions) {
160
+ if (!options) return undefined;
161
+ const { speed } = options;
162
+ const repeatField = options.repeat;
163
+ if (repeatField === undefined) {
164
+ return { speed };
165
+ }
166
+ if (repeatField === 'nonRepeating') {
167
+ return { repeatKind: 'nonRepeating' as const, speed };
168
+ }
169
+ if (repeatField === 'continuous') {
170
+ return { repeatKind: 'continuous' as const, speed };
171
+ }
172
+ return {
173
+ repeatKind: 'periodic' as const,
174
+ repeatCount: repeatField.count,
175
+ repeatDelay: repeatField.delay,
176
+ speed,
177
+ };
178
+ }
179
+
180
+ // exported for docs api data
181
+ export { type ObservableState };
@@ -7,6 +7,7 @@ declare module 'react-native' {
7
7
  ) => React.ReactElement<P>;
8
8
 
9
9
  type DisplayValue = ReactNative.FlexStyle['display'] | 'inline-flex';
10
+ type WebDimensionValue = ReactNative.DimensionValue | string;
10
11
 
11
12
  type WebRole =
12
13
  | ReactNative.Role
@@ -95,18 +96,37 @@ declare module 'react-native' {
95
96
  }
96
97
 
97
98
  export interface ViewProps extends WebAccessibilityProps {
99
+ dir?: string;
98
100
  role?: WebRole;
99
101
  }
100
102
 
101
103
  export interface ImageStyle {
102
104
  display?: DisplayValue;
105
+ height?: WebDimensionValue;
106
+ width?: WebDimensionValue;
107
+ paddingLeft?: WebDimensionValue;
108
+ paddingRight?: WebDimensionValue;
109
+ paddingTop?: WebDimensionValue;
110
+ paddingBottom?: WebDimensionValue;
103
111
  }
104
112
 
105
113
  export interface TextStyle {
106
114
  display?: DisplayValue;
115
+ height?: WebDimensionValue;
116
+ width?: WebDimensionValue;
117
+ paddingLeft?: WebDimensionValue;
118
+ paddingRight?: WebDimensionValue;
119
+ paddingTop?: WebDimensionValue;
120
+ paddingBottom?: WebDimensionValue;
107
121
  }
108
122
 
109
123
  export interface ViewStyle {
110
124
  display?: DisplayValue;
125
+ height?: WebDimensionValue;
126
+ width?: WebDimensionValue;
127
+ paddingLeft?: WebDimensionValue;
128
+ paddingRight?: WebDimensionValue;
129
+ paddingTop?: WebDimensionValue;
130
+ paddingBottom?: WebDimensionValue;
111
131
  }
112
132
  }
@@ -1,17 +1,82 @@
1
- import { View, type ViewProps } from 'react-native';
1
+ import { StyleSheet, View, type LayoutChangeEvent, type ViewProps } from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ matchContents: {
5
+ alignSelf: 'flex-start',
6
+ },
7
+ matchViewport: {
8
+ height: '100dvh',
9
+ width: '100dvw',
10
+ },
11
+ safeArea: {
12
+ paddingLeft: 'max(env(safe-area-inset-left, 0px), env(keyboard-inset-left, 0px))',
13
+ paddingRight: 'max(env(safe-area-inset-right, 0px), env(keyboard-inset-right, 0px))',
14
+ paddingTop: 'max(env(safe-area-inset-top, 0px), env(keyboard-inset-top, 0px))',
15
+ paddingBottom: 'max(env(safe-area-inset-bottom, 0px), env(keyboard-inset-bottom, 0px))',
16
+ },
17
+ safeAreaWithoutKeyboard: {
18
+ paddingLeft: 'env(safe-area-inset-left, 0px)',
19
+ paddingRight: 'env(safe-area-inset-right, 0px)',
20
+ paddingTop: 'env(safe-area-inset-top, 0px)',
21
+ paddingBottom: 'env(safe-area-inset-bottom, 0px)',
22
+ },
23
+ });
24
+
25
+ type HostProps = {
26
+ ignoreSafeArea?: 'all' | 'keyboard';
27
+ layoutDirection?: 'leftToRight' | 'rightToLeft';
28
+ matchContents?: boolean | { horizontal?: boolean; vertical?: boolean };
29
+ onLayoutContent?: (event: { nativeEvent: { width: number; height: number } }) => void;
30
+ useViewportSizeMeasurement?: boolean;
31
+ };
2
32
 
3
33
  /**
4
34
  * A bridging container that hosts SwiftUI views on iOS and Jetpack Compose views on Android.
5
35
  */
6
36
  export function Host({
7
37
  children,
38
+ ignoreSafeArea,
39
+ layoutDirection,
40
+ matchContents = false,
41
+ onLayout,
42
+ onLayoutContent,
8
43
  style,
44
+ useViewportSizeMeasurement = false,
9
45
  ...rest
10
- }: ViewProps & {
11
- matchContents?: boolean | { vertical?: boolean; horizontal?: boolean };
12
- }) {
46
+ }: ViewProps & HostProps) {
47
+ const shouldMatchContents =
48
+ typeof matchContents === 'object'
49
+ ? matchContents.horizontal || matchContents.vertical
50
+ : matchContents;
51
+
13
52
  return (
14
- <View style={style} {...rest}>
53
+ <View
54
+ dir={
55
+ layoutDirection === 'leftToRight'
56
+ ? 'ltr'
57
+ : layoutDirection === 'rightToLeft'
58
+ ? 'rtl'
59
+ : undefined
60
+ }
61
+ onLayout={(event: LayoutChangeEvent) => {
62
+ onLayout?.(event);
63
+
64
+ onLayoutContent?.({
65
+ nativeEvent: {
66
+ width: event.nativeEvent.layout.width,
67
+ height: event.nativeEvent.layout.height,
68
+ },
69
+ });
70
+ }}
71
+ style={[
72
+ ignoreSafeArea !== 'all' &&
73
+ (ignoreSafeArea === 'keyboard' ? styles.safeAreaWithoutKeyboard : styles.safeArea),
74
+ shouldMatchContents
75
+ ? styles.matchContents
76
+ : useViewportSizeMeasurement && styles.matchViewport,
77
+ style,
78
+ ]}
79
+ {...rest}>
15
80
  {children}
16
81
  </View>
17
82
  );
@@ -1 +0,0 @@
1
- a534f795e8ea46629011b2f8939608619b954ff1
@@ -1 +0,0 @@
1
- 213a1693673392a710d27fef37d99ef030c8a8783b4ccaa971ea914588dc5241
@@ -1 +0,0 @@
1
- 26e067865e2bbdd9f770d670f8212c2a309bee05009f722931b339ca9f76c235bbed2286a876d9c7a7b0ddb0e4b152617031f487c047ae78d0672ecc2649c6be
@@ -1 +0,0 @@
1
- ea2684e30595f6e153476b3bd38b40f7
@@ -1 +0,0 @@
1
- 63505c031167b651fcd2b3ed1cddbcb5a014bfa8
@@ -1 +0,0 @@
1
- 05e8833b0c8b22442fa1d70cd203ec9f986fd4e9d8541393c843779bca1bed6a
@@ -1 +0,0 @@
1
- 2214ac6df49634ec222a3563eb91161f0ba5977ea600f354473f9dd5d166dd79b5230c634d59c15fe027d77f9010fd3d984718d4c392adf444acf687e40e076e
@@ -1 +0,0 @@
1
- aa1f1c7ec449e0d76d64fc008bf3af9d9928e0da
@@ -1 +0,0 @@
1
- e15fb389c9d21d25522483c1e58b1cc0a57ec2b0ee710c49bd79528c3faa467a
@@ -1 +0,0 @@
1
- dec030fd37a92340a477da17d8da83a39d8b2f1cdfbf66754d56f9c6b7152d125aeaa8438f0b7247d945acc9723dcceaa74a22e059ded7bd2dc784cad21732d0
@@ -1 +0,0 @@
1
- 08e2d6fe28ff36a46db43b08826921cb
@@ -1 +0,0 @@
1
- e27605954788d0a858a8a8c98d859cb19fb284cb
@@ -1 +0,0 @@
1
- b634c2eaed8ad38f4446b1b0d1131dd73a5a596c3e94a4a8d104ffb19cb32308
@@ -1 +0,0 @@
1
- 0ab0a808565b2c2ee6a962b8ede40b90325253d03b617d4cc0c8954283946e82dca663d89c15a7fcaed0c8457fb43de6f5fbc743a4286ee4016dcb7dfc94c196