@expo/ui 58.0.12 → 58.0.13

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 (80) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/DatePickerView.kt +1 -0
  4. package/build/State/index.d.ts +1 -0
  5. package/build/State/index.js +1 -0
  6. package/build/State/index.js.map +1 -1
  7. package/build/State/useWorkletCallback.d.ts +31 -0
  8. package/build/State/useWorkletCallback.js +30 -0
  9. package/build/State/useWorkletCallback.js.map +1 -0
  10. package/build/jetpack-compose/index.d.ts +1 -1
  11. package/build/jetpack-compose/index.js +1 -1
  12. package/build/jetpack-compose/index.js.map +1 -1
  13. package/build/swift-ui/ArrangementView/index.d.ts +48 -0
  14. package/build/swift-ui/ArrangementView/index.js +56 -0
  15. package/build/swift-ui/ArrangementView/index.js.map +1 -0
  16. package/build/swift-ui/index.d.ts +2 -1
  17. package/build/swift-ui/index.js +2 -1
  18. package/build/swift-ui/index.js.map +1 -1
  19. package/build/swift-ui/modifiers/arrangementModifiers.d.ts +109 -0
  20. package/build/swift-ui/modifiers/arrangementModifiers.js +35 -0
  21. package/build/swift-ui/modifiers/arrangementModifiers.js.map +1 -0
  22. package/build/swift-ui/modifiers/hingeObservation.d.ts +73 -0
  23. package/build/swift-ui/modifiers/hingeObservation.js +45 -0
  24. package/build/swift-ui/modifiers/hingeObservation.js.map +1 -0
  25. package/build/swift-ui/modifiers/index.d.ts +4 -1
  26. package/build/swift-ui/modifiers/index.js +2 -0
  27. package/build/swift-ui/modifiers/index.js.map +1 -1
  28. package/ios/ArrangementViewView.swift +40 -0
  29. package/ios/ExpoUIModule.swift +1 -0
  30. package/ios/Modifiers/ArrangementModifiers.swift +157 -0
  31. package/ios/Modifiers/HingeObservationModifiers.swift +82 -0
  32. package/ios/Modifiers/ViewModifierRegistry.swift +28 -3
  33. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.12/expo.modules.ui-58.0.12-sources.jar → 58.0.13/expo.modules.ui-58.0.13-sources.jar} +0 -0
  34. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.md5 +1 -0
  35. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha1 +1 -0
  36. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha256 +1 -0
  37. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13-sources.jar.sha512 +1 -0
  38. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar +0 -0
  39. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.md5 +1 -0
  40. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha1 +1 -0
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha256 +1 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.aar.sha512 +1 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.12/expo.modules.ui-58.0.12.module → 58.0.13/expo.modules.ui-58.0.13.module} +22 -22
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.md5 +1 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha1 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha256 +1 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.module.sha512 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.12/expo.modules.ui-58.0.12.pom → 58.0.13/expo.modules.ui-58.0.13.pom} +1 -1
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.md5 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha1 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha256 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.13/expo.modules.ui-58.0.13.pom.sha512 +1 -0
  53. package/package.json +2 -2
  54. package/prebuilds/output/debug/xcframeworks/ExpoUI.tar.gz +0 -0
  55. package/prebuilds/output/release/xcframeworks/ExpoUI.tar.gz +0 -0
  56. package/src/State/index.ts +1 -0
  57. package/src/State/useWorkletCallback.ts +48 -0
  58. package/src/jetpack-compose/index.ts +1 -1
  59. package/src/swift-ui/ArrangementView/index.tsx +70 -0
  60. package/src/swift-ui/index.tsx +2 -1
  61. package/src/swift-ui/modifiers/arrangementModifiers.ts +142 -0
  62. package/src/swift-ui/modifiers/hingeObservation.ts +91 -0
  63. package/src/swift-ui/modifiers/index.ts +4 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12-sources.jar.md5 +0 -1
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12-sources.jar.sha1 +0 -1
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12-sources.jar.sha256 +0 -1
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12-sources.jar.sha512 +0 -1
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.aar +0 -0
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.aar.md5 +0 -1
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.aar.sha1 +0 -1
  71. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.aar.sha256 +0 -1
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.aar.sha512 +0 -1
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.module.md5 +0 -1
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.module.sha1 +0 -1
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.module.sha256 +0 -1
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.module.sha512 +0 -1
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.pom.md5 +0 -1
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.pom.sha1 +0 -1
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.pom.sha256 +0 -1
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.12/expo.modules.ui-58.0.12.pom.sha512 +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "58.0.12",
3
+ "version": "58.0.13",
4
4
  "description": "A collection of UI components",
5
5
  "keywords": [
6
6
  "Jetpack Compose",
@@ -148,7 +148,7 @@
148
148
  "@types/jest": "^30.0.0",
149
149
  "@types/node": "^22.14.0",
150
150
  "@types/react": "~19.3.0",
151
- "expo-module-scripts": "56.0.6",
151
+ "expo-module-scripts": "56.0.7",
152
152
  "react-native-reanimated": "4.7.0",
153
153
  "react-native-worklets": "0.13.0"
154
154
  },
@@ -6,5 +6,6 @@ import './index.fx';
6
6
 
7
7
  export { useNativeState, type ObservableState } from './useNativeState';
8
8
  export { useWorkletProp } from './useWorkletProp';
9
+ export { useWorkletCallback, type WorkletCallback } from './useWorkletCallback';
9
10
  export { worklets } from './optionalWorklets';
10
11
  export { getStateId } from './utils';
@@ -0,0 +1,48 @@
1
+ import type { SharedObject } from 'expo';
2
+
3
+ import { worklets } from './optionalWorklets';
4
+ import { useWorkletProp } from './useWorkletProp';
5
+
6
+ /**
7
+ * A worklet function wrapped for native code, returned by [`useWorkletCallback`](#useworkletcallback).
8
+ * Pass it to a modifier or prop that accepts worklet callbacks, which then runs it synchronously on
9
+ * the UI thread.
10
+ */
11
+ export type WorkletCallback<T extends (...args: never[]) => void> = SharedObject & {
12
+ /** @hidden */
13
+ readonly __workletCallbackType?: T;
14
+ };
15
+
16
+ /**
17
+ * Wraps a worklet function so native code can run it synchronously on the UI thread, with no
18
+ * JS-thread round trip. Pass the result to a modifier that accepts worklet callbacks, such as
19
+ * `onHingeChange`. The callback must start with the `'worklet'` directive, and
20
+ * [`react-native-worklets`](https://docs.swmansion.com/react-native-worklets/) must be installed.
21
+ *
22
+ * The native callback is updated when `callback` changes and released when the component unmounts,
23
+ * so call it at the top of your component like any hook.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const angle = useNativeState(180);
28
+ * const onHinge = useWorkletCallback((_, newContext) => {
29
+ * 'worklet';
30
+ * angle.value = newContext.hinge?.angle ?? 180;
31
+ * });
32
+ *
33
+ * <VStack modifiers={[onHingeChange(onHinge)]} />
34
+ * ```
35
+ */
36
+ export function useWorkletCallback<T extends (...args: never[]) => void>(
37
+ callback: T
38
+ ): WorkletCallback<T> {
39
+ const workletCallback = useWorkletProp(callback as unknown as (...args: unknown[]) => void);
40
+ if (!worklets || !workletCallback) {
41
+ throw new Error(
42
+ "useWorkletCallback needs the 'react-native-worklets' package, which couldn't be loaded. " +
43
+ 'Install react-native-worklets and rebuild the native app, or pass a plain function ' +
44
+ 'where the API accepts one.'
45
+ );
46
+ }
47
+ return workletCallback as WorkletCallback<T>;
48
+ }
@@ -72,6 +72,6 @@ export * from './Box';
72
72
  export * from './Row';
73
73
  export * from './Column';
74
74
  export * from './FlowRow';
75
- export { useNativeState } from '../State';
75
+ export { useNativeState, useWorkletCallback, type WorkletCallback } from '../State';
76
76
  export type { ViewEvent } from '../types';
77
77
  export type { PrimitiveBaseProps } from './layout-types';
@@ -0,0 +1,70 @@
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 interface ArrangementViewProps extends CommonViewModifierProps {
8
+ /**
9
+ * The views to arrange. Provide `ArrangementView.Primary` and `ArrangementView.Secondary`.
10
+ */
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ const ArrangementViewNativeView: React.ComponentType<ArrangementViewProps> = requireNativeView(
15
+ 'ExpoUI',
16
+ 'ArrangementViewView'
17
+ );
18
+
19
+ /**
20
+ * The primary view of the arrangement.
21
+ */
22
+ function ArrangementViewPrimary(props: { children: React.ReactNode }) {
23
+ return <Slot name="primary">{props.children}</Slot>;
24
+ }
25
+
26
+ /**
27
+ * The secondary view of the arrangement.
28
+ */
29
+ function ArrangementViewSecondary(props: { children: React.ReactNode }) {
30
+ return <Slot name="secondary">{props.children}</Slot>;
31
+ }
32
+
33
+ ArrangementView.Primary = ArrangementViewPrimary;
34
+ ArrangementView.Secondary = ArrangementViewSecondary;
35
+
36
+ /**
37
+ * ArrangementView uses the native [ArrangementView](https://developer.apple.com/documentation/swiftui/arrangementview) view.
38
+ *
39
+ * A view that arranges primary and secondary content using an adaptive layout that responds to
40
+ * the environment.
41
+ *
42
+ * > **Note:** Below iOS 27.1, the children render without a container.
43
+ * @example
44
+ * ```tsx
45
+ * <Host style={{ flex: 1 }}>
46
+ * <ArrangementView modifiers={[arrangementViewStyle('split')]}>
47
+ * <ArrangementView.Primary>
48
+ * <NowPlaying />
49
+ * </ArrangementView.Primary>
50
+ * <ArrangementView.Secondary>
51
+ * <Lyrics />
52
+ * </ArrangementView.Secondary>
53
+ * </ArrangementView>
54
+ * </Host>
55
+ * ```
56
+ * @platform ios 27.1+
57
+ * @platform tvos 27.1+
58
+ */
59
+ export function ArrangementView(props: ArrangementViewProps) {
60
+ const { modifiers, children, ...restProps } = props;
61
+
62
+ return (
63
+ <ArrangementViewNativeView
64
+ modifiers={modifiers}
65
+ {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
66
+ {...restProps}>
67
+ {children}
68
+ </ArrangementViewNativeView>
69
+ );
70
+ }
@@ -29,6 +29,7 @@ export * from './Menu';
29
29
  export * from './NavigationDestination';
30
30
  export * from './NavigationLink';
31
31
  export * from './NavigationSplitView';
32
+ export * from './ArrangementView';
32
33
  export * from './NavigationStack';
33
34
  export * from './Picker';
34
35
  export * from './ProgressView';
@@ -39,7 +40,7 @@ export * from './Spacer';
39
40
  export * from './Stepper';
40
41
  export * from './SwipeActions';
41
42
  export * from './Text';
42
- export { useNativeState } from '../State';
43
+ export { useNativeState, useWorkletCallback, type WorkletCallback } from '../State';
43
44
  export { withAnimation, type WithAnimationCompletionCriteria } from './withAnimation';
44
45
  export * from './SyncToggle';
45
46
  export * from './TabView';
@@ -0,0 +1,142 @@
1
+ import { createModifier } from './createModifier';
2
+
3
+ /**
4
+ * A style that configures an `ArrangementView` with an arrangement.
5
+ * - `'automatic'`: The default style, which resolves to `'split'`.
6
+ * - `'split'`: An arrangement view style that places the primary and secondary views side by side along one or more axes.
7
+ * - `'overlay'`: An arrangement view style that layers the primary view over the secondary view in z-order.
8
+ */
9
+ export type ArrangementViewStyle = 'automatic' | 'split' | 'overlay';
10
+
11
+ /**
12
+ * Sets the style for arrangement views within this view.
13
+ * @param style - The style to apply.
14
+ * @param options - The `axes` the arrangement supports. With `'split'`, creates a split arrangement
15
+ * that supports the given axes. With `'overlay'`, creates an overlay arrangement that supports
16
+ * laying out its views along the given axes.
17
+ * @platform ios 27.1+
18
+ * @platform tvos 27.1+
19
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/arrangementviewstyle(_:)).
20
+ */
21
+ export function arrangementViewStyle(style: 'automatic'): ReturnType<typeof createModifier>;
22
+ export function arrangementViewStyle(
23
+ style: 'split' | 'overlay',
24
+ options?: { axes?: 'horizontal' | 'vertical' | 'both' }
25
+ ): ReturnType<typeof createModifier>;
26
+ export function arrangementViewStyle(
27
+ style: ArrangementViewStyle,
28
+ options?: { axes?: 'horizontal' | 'vertical' | 'both' }
29
+ ) {
30
+ return createModifier('arrangementViewStyle', { style, axes: options?.axes });
31
+ }
32
+
33
+ /**
34
+ * The minimum, ideal, and maximum ratios for `splitArrangementLayoutRatio`.
35
+ */
36
+ export type SplitArrangementLayoutRatioParams = {
37
+ minHorizontal?: number;
38
+ idealHorizontal?: number;
39
+ maxHorizontal?: number;
40
+ minVertical?: number;
41
+ idealVertical?: number;
42
+ maxVertical?: number;
43
+ };
44
+
45
+ /**
46
+ * Sets the preferred size ratio for the content of `ArrangementView.Primary` or
47
+ * `ArrangementView.Secondary` in a split arrangement.
48
+ * @platform ios 27.1+
49
+ * @platform tvos 27.1+
50
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/splitarrangementlayoutratio(_:)).
51
+ */
52
+ export function splitArrangementLayoutRatio(ratio: number): ReturnType<typeof createModifier>;
53
+ /**
54
+ * Sets the size ratio for the content of `ArrangementView.Primary` or `ArrangementView.Secondary`
55
+ * in a split arrangement.
56
+ * @platform ios 27.1+
57
+ * @platform tvos 27.1+
58
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/splitarrangementlayoutratio(minhorizontal:idealhorizontal:maxhorizontal:minvertical:idealvertical:maxvertical:)).
59
+ */
60
+ export function splitArrangementLayoutRatio(
61
+ ratios: SplitArrangementLayoutRatioParams
62
+ ): ReturnType<typeof createModifier>;
63
+ export function splitArrangementLayoutRatio(
64
+ ratioOrParams: number | SplitArrangementLayoutRatioParams
65
+ ) {
66
+ return createModifier(
67
+ 'splitArrangementLayoutRatio',
68
+ typeof ratioOrParams === 'number' ? { ratio: ratioOrParams } : ratioOrParams
69
+ );
70
+ }
71
+
72
+ /**
73
+ * The minimum, ideal, and maximum sizes for `splitArrangementLayoutSize`.
74
+ */
75
+ export type SplitArrangementLayoutSizeParams = {
76
+ minWidth?: number;
77
+ idealWidth?: number;
78
+ maxWidth?: number;
79
+ minHeight?: number;
80
+ idealHeight?: number;
81
+ maxHeight?: number;
82
+ };
83
+
84
+ /**
85
+ * Sets the size constraints for the content of `ArrangementView.Primary` or
86
+ * `ArrangementView.Secondary` in a split arrangement.
87
+ * @platform ios 27.1+
88
+ * @platform tvos 27.1+
89
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/splitarrangementlayoutsize(minwidth:idealwidth:maxwidth:minheight:idealheight:maxheight:)).
90
+ */
91
+ export const splitArrangementLayoutSize = (constraints: SplitArrangementLayoutSizeParams) =>
92
+ createModifier('splitArrangementLayoutSize', constraints);
93
+
94
+ /**
95
+ * The split axes on which `splitArrangementFixedLayoutSize` prefers the ideal size of the view.
96
+ */
97
+ export type SplitArrangementFixedLayoutSizeParams = {
98
+ /**
99
+ * Whether to prefer a fixed width for the view in a horizontal split.
100
+ * @default true
101
+ */
102
+ horizontal?: boolean;
103
+ /**
104
+ * Whether to prefer a fixed height for the view in a vertical split.
105
+ * @default true
106
+ */
107
+ vertical?: boolean;
108
+ };
109
+
110
+ /**
111
+ * Sets the preferred size constraint for the content of `ArrangementView.Primary` or
112
+ * `ArrangementView.Secondary` in a split arrangement to the ideal size of the view within its
113
+ * container. The arrangement view prefers this size, but may resize to a smaller size depending on
114
+ * the priority of the view.
115
+ * @platform ios 27.1+
116
+ * @platform tvos 27.1+
117
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/splitarrangementfixedlayoutsize(horizontal:vertical:)).
118
+ */
119
+ export const splitArrangementFixedLayoutSize = (options?: SplitArrangementFixedLayoutSizeParams) =>
120
+ createModifier('splitArrangementFixedLayoutSize', options);
121
+
122
+ /**
123
+ * Sets the horizontal edge that a view in an overlay arrangement occupies when the arrangement
124
+ * transitions to a horizontal layout.
125
+ * @platform ios 27.1+
126
+ * @platform tvos 27.1+
127
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/overlayarrangementedge(_:)).
128
+ */
129
+ export function overlayArrangementEdge(
130
+ edge: 'leading' | 'trailing'
131
+ ): ReturnType<typeof createModifier>;
132
+ /**
133
+ * Sets the vertical edge that a view in an overlay arrangement occupies when the arrangement
134
+ * transitions to a vertical layout.
135
+ * @platform ios 27.1+
136
+ * @platform tvos 27.1+
137
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/overlayarrangementedge(_:)-4tjwn).
138
+ */
139
+ export function overlayArrangementEdge(edge: 'top' | 'bottom'): ReturnType<typeof createModifier>;
140
+ export function overlayArrangementEdge(edge: 'top' | 'bottom' | 'leading' | 'trailing') {
141
+ return createModifier('overlayArrangementEdge', { edge });
142
+ }
@@ -0,0 +1,91 @@
1
+ import { getStateId, type WorkletCallback } from '../../State';
2
+ import { createModifier, createModifierWithEventListener } from './createModifier';
3
+
4
+ /**
5
+ * Status of the device hinge, as reported by SwiftUI's `DeviceHinge.Status`.
6
+ * `'unknown'` is reserved for a status this version of Expo UI does not recognize.
7
+ * @platform ios 27.1+
8
+ */
9
+ export type HingeStatus = 'closed' | 'partiallyOpen' | 'fullyOpen' | 'unknown';
10
+
11
+ /**
12
+ * State of the device hinge. Mirrors SwiftUI's `DeviceHinge`.
13
+ * @platform ios 27.1+
14
+ */
15
+ export type Hinge = {
16
+ /**
17
+ * The current angle of the hinge in degrees, where `0` is closed and `180` is flat. The rate and
18
+ * granularity of angle updates are system policy, so do not depend on a particular update
19
+ * frequency or precision. Prefer `status` when you only need to know whether the hinge is closed,
20
+ * partially open, or fully open.
21
+ */
22
+ angle: number;
23
+ /**
24
+ * The current status of the hinge, determined by the system from the angle and device orientation.
25
+ */
26
+ status: HingeStatus;
27
+ };
28
+
29
+ /**
30
+ * The hinge context of the view hierarchy. Mirrors SwiftUI's `DeviceHingeContext`.
31
+ * @platform ios 27.1+
32
+ */
33
+ export type HingeContext = {
34
+ /**
35
+ * The current hinge, or `null` when the device has no hinge or the view's hierarchy provides no
36
+ * hinge updates.
37
+ */
38
+ hinge: Hinge | null;
39
+ };
40
+
41
+ /**
42
+ * A function called with the old and the new hinge context when the hinge context changes.
43
+ */
44
+ export type HingeChangeHandler = (oldContext: HingeContext, newContext: HingeContext) => void;
45
+
46
+ /**
47
+ * Calls the handler when the hinge context of the view hierarchy changes, such as when the user
48
+ * folds or unfolds the device. The handler receives the old and the new context. Use hinge
49
+ * state for interactions and effects, not for layout.
50
+ *
51
+ * Pass a plain function to run it on the JS thread, or a callback from
52
+ * [`useWorkletCallback`](../usenativestate/#useworkletcallback) to run it synchronously on the UI
53
+ * thread, which suits driving a native state value from the continuous `angle`.
54
+ *
55
+ * The first call happens when the view appears, and its old context has a `null` hinge. On devices
56
+ * without a hinge, both contexts have a `null` hinge. The modifier is a no-op on iOS versions earlier
57
+ * than 27.1 and in builds made with Xcode earlier than 27.1.
58
+ *
59
+ * @param handler - Function or worklet callback called with the old and the new hinge context.
60
+ * @platform ios 27.1+
61
+ *
62
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/onhingechange(isenabled:_:)).
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * // JS thread
67
+ * const [hinge, setHinge] = useState<Hinge | null>(null);
68
+ * <VStack modifiers={[onHingeChange((_, newContext) => setHinge(newContext.hinge))]} />
69
+ *
70
+ * // UI thread
71
+ * const angle = useNativeState(180);
72
+ * const onHinge = useWorkletCallback((_, newContext) => {
73
+ * 'worklet';
74
+ * angle.value = newContext.hinge?.angle ?? 180;
75
+ * });
76
+ * <VStack modifiers={[onHingeChange(onHinge)]} />
77
+ * ```
78
+ */
79
+ export const onHingeChange = (
80
+ handler: HingeChangeHandler | WorkletCallback<HingeChangeHandler>
81
+ ) => {
82
+ if (typeof handler !== 'function') {
83
+ return createModifier('onHingeChange', { workletCallback: getStateId(handler) });
84
+ }
85
+ const callback = handler as HingeChangeHandler;
86
+ return createModifierWithEventListener(
87
+ 'onHingeChange',
88
+ (event: { oldContext: HingeContext; newContext: HingeContext }) =>
89
+ callback(event.oldContext, event.newContext)
90
+ );
91
+ };
@@ -18,6 +18,7 @@ import {
18
18
  import { datePickerStyle } from './datePickerStyle';
19
19
  import { environment } from './environment';
20
20
  import { gaugeStyle } from './gaugeStyle';
21
+ import { onHingeChange } from './hingeObservation';
21
22
  import { progressViewStyle } from './progressViewStyle';
22
23
  import { onScrollPhaseChange, useScrollGeometryChange } from './scrollObservation';
23
24
  import { id, scrollPosition } from './scrollPosition';
@@ -1896,6 +1897,7 @@ export type BuiltInModifier =
1896
1897
  | ReturnType<typeof scrollPosition>
1897
1898
  | ReturnType<typeof onScrollPhaseChange>
1898
1899
  | NonNullable<ReturnType<typeof useScrollGeometryChange>>
1900
+ | ReturnType<typeof onHingeChange>
1899
1901
  | ReturnType<typeof moveDisabled>
1900
1902
  | ReturnType<typeof deleteDisabled>
1901
1903
  | ReturnType<typeof environment>
@@ -1989,6 +1991,7 @@ export * from './pickerStyle';
1989
1991
  export * from './menuOrder';
1990
1992
  export * from './tabViewModifiers';
1991
1993
  export * from './navigationModifiers';
1994
+ export * from './arrangementModifiers';
1992
1995
  export * from './datePickerStyle';
1993
1996
  export * from './progressViewStyle';
1994
1997
  export * from './gaugeStyle';
@@ -1998,6 +2001,7 @@ export type { ShapeStyle } from './shapeStyle';
1998
2001
  export * from './scrollPosition';
1999
2002
  export * from './symbolEffect';
2000
2003
  export * from './scrollObservation';
2004
+ export * from './hingeObservation';
2001
2005
  export * from './widgets';
2002
2006
  export type {
2003
2007
  TimingAnimationParams,
@@ -1 +0,0 @@
1
- 35f9c28864e4c66ebf31d87331aaf606420295dd
@@ -1 +0,0 @@
1
- d6b5917f7e254bed3b859860b39f0cf57b943148a0dc5c25282599caaa5bbf7e
@@ -1 +0,0 @@
1
- 7325da1dbb0f220f807982fa7797678dba275209f74efde81b39d4ecf3452573708a111629552ae98257631d5c8e9d26438d10a50172c6d731e247d20f8762c0
@@ -1 +0,0 @@
1
- 552a8fdfc1afb51afb7bf9f742f2917988ccb39d
@@ -1 +0,0 @@
1
- 3c1582041a0a49f0df088ad60c5ee3c2333da74afff9a783f4e31984ef5f975d
@@ -1 +0,0 @@
1
- 453c085a9a3f87728a04202f8345587720468598c7873813e572b87013ff025c384008e4c77d5ca54db253df56b5545b6180aec60b0164afce10cb1ad8c128cc
@@ -1 +0,0 @@
1
- 433a597cd6dca38ee4d54004b360b6a3bf70ba82
@@ -1 +0,0 @@
1
- 2a815ceefba6faf7b58914bfe44a837a1ad50d0e9c5897547cbe10224dabb515
@@ -1 +0,0 @@
1
- ebf577ea4efcff86cca51e6b9397ad95b4fe3c9c1096f713141e11ec062e9be4026a253409a70b083779125211584cfb607049a0ecad3b96e1629f66c784e0ec
@@ -1 +0,0 @@
1
- de2eee349bef3b70e3c4ffcc4655fe3e01a9345d
@@ -1 +0,0 @@
1
- 98d3376b217927f0da992180fc5c046f3262f215ea3259c615c8692d57064d5c
@@ -1 +0,0 @@
1
- 8781d05212c66bce3d8fd208c166c960a71112eac576c5335d6bfb4627f278b97b5ddedc8c54e855bd23610bef563ec1b6a00c676fbedd27943df33cf552492c