expo-widgets 58.0.9 → 58.0.10
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 +9 -0
- package/android/build.gradle +3 -3
- package/android/src/main/java/expo/modules/widgets/ExpoWidgetEmittableTree.kt +1 -1
- package/android/src/main/java/expo/modules/widgets/ExpoWidgetsAppWidgetProvider.kt +1 -1
- package/android/src/main/java/expo/modules/widgets/ExpoWidgetsPeekWidget.kt +1 -1
- package/bundle/react-stub.ts +67 -6
- package/expo-module.config.json +3 -3
- package/ios/Widgets/AccessoryWidgetBackgroundView.swift +28 -0
- package/ios/Widgets/WidgetModifiers.swift +102 -0
- package/ios/WidgetsContext.swift +4 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 58.0.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add React hook and component helper stubs to prevent missing API errors when rendering widgets, including `memo` and `forwardRef`. ([#50834](https://github.com/expo/expo/pull/50834) by [@jakex7](https://github.com/jakex7))
|
|
8
|
+
- [iOS] Stop linking WidgetKit into apps that use `@expo/ui` without widgets. The `widgetURL`, `activityBackgroundTint`, `widgetAccentedRenderingMode`, and `containerBackground` (`widget` placement) modifiers and the `AccessoryWidgetBackground` view now take effect only inside `expo-widgets` widgets and Live Activities. ([#50786](https://github.com/expo/expo/pull/50786) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
9
|
+
- Updated dependencies. ([#50801](https://github.com/expo/expo/pull/50801), [#49986](https://github.com/expo/expo/pull/49986), [#50674](https://github.com/expo/expo/pull/50674), [#50786](https://github.com/expo/expo/pull/50786), [#50851](https://github.com/expo/expo/pull/50851))
|
|
10
|
+
- @expo/ui@58.0.10
|
|
11
|
+
|
|
3
12
|
## 58.0.9
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/android/build.gradle
CHANGED
|
@@ -6,7 +6,7 @@ plugins {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
group = 'expo.modules.widgets'
|
|
9
|
-
version = '58.0.
|
|
9
|
+
version = '58.0.10'
|
|
10
10
|
|
|
11
11
|
def expoWidgetsPackageDirFile = project.projectDir.parentFile
|
|
12
12
|
def expoWidgetsPackageDir = expoWidgetsPackageDirFile.absolutePath
|
|
@@ -39,7 +39,7 @@ android {
|
|
|
39
39
|
namespace "expo.modules.widgets"
|
|
40
40
|
defaultConfig {
|
|
41
41
|
versionCode 1
|
|
42
|
-
versionName '58.0.
|
|
42
|
+
versionName '58.0.10'
|
|
43
43
|
|
|
44
44
|
externalNativeBuild {
|
|
45
45
|
cmake {
|
|
@@ -143,6 +143,6 @@ dependencies {
|
|
|
143
143
|
implementation 'com.facebook.react:react-android'
|
|
144
144
|
implementation 'com.facebook.react:hermes-android'
|
|
145
145
|
implementation expoModule.getExpoDependency("expo-ui")
|
|
146
|
-
api 'io.github.
|
|
146
|
+
api 'io.github.expo.peek:peek-emittables:0.3.1'
|
|
147
147
|
implementation "androidx.glance:glance:1.2.0"
|
|
148
148
|
}
|
|
@@ -105,7 +105,7 @@ import androidx.glance.unit.ColorProvider
|
|
|
105
105
|
import androidx.glance.appwidget.lazy.EmittableLazyColumn
|
|
106
106
|
import androidx.glance.appwidget.lazy.EmittableLazyListItem
|
|
107
107
|
import androidx.glance.appwidget.lazy.ReservedItemIdRangeEnd
|
|
108
|
-
import io.github.
|
|
108
|
+
import io.github.expo.peek.glance.determinateCircularProgressIndicatorEmittable
|
|
109
109
|
import kotlin.math.roundToInt
|
|
110
110
|
|
|
111
111
|
private val DefaultCheckedColor = ColorProvider(Color(0xff6750a4))
|
|
@@ -3,7 +3,7 @@ package expo.modules.widgets
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.content.Intent
|
|
5
5
|
import androidx.glance.appwidget.GlanceAppWidgetReceiver
|
|
6
|
-
import io.github.
|
|
6
|
+
import io.github.expo.peek.emittables.PeekEmittableAppWidget
|
|
7
7
|
|
|
8
8
|
open class ExpoWidgetsAppWidgetProvider(
|
|
9
9
|
widgetName: String
|
|
@@ -8,7 +8,7 @@ import androidx.compose.ui.unit.DpSize
|
|
|
8
8
|
import androidx.glance.Emittable
|
|
9
9
|
import androidx.glance.appwidget.AppWidgetId
|
|
10
10
|
import androidx.glance.appwidget.SizeMode
|
|
11
|
-
import io.github.
|
|
11
|
+
import io.github.expo.peek.emittables.PeekEmittableAppWidget
|
|
12
12
|
|
|
13
13
|
internal class ExpoWidgetsPeekWidget(
|
|
14
14
|
private val widgetName: String
|
package/bundle/react-stub.ts
CHANGED
|
@@ -15,16 +15,77 @@ export const isValidElement = (value: unknown): value is ReactElementNode => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// TODO(@jakex7): Make this a proper React reconciler in the future. For now, we just need a stub to allow the widget bundle to compile with @expo/ui/jetpack-compose.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
|
|
19
|
+
// Each widget render is a fresh mount, so there is nothing to memoize.
|
|
20
|
+
export const memo = (component: any, _arePropsEqual?: any) => component;
|
|
21
|
+
export const forwardRef = (render: any) => (props: any) => {
|
|
22
|
+
const { ref = null, ...rest } = props;
|
|
23
|
+
return render(rest, ref);
|
|
22
24
|
};
|
|
25
|
+
export const createRef = (): any => ({ current: null });
|
|
26
|
+
export function createElement(type: any, config?: any, ...children: any[]) {
|
|
27
|
+
const { key, ...props } = config ?? {};
|
|
28
|
+
if (children.length > 0) {
|
|
29
|
+
props.children = children.length === 1 ? children[0] : children;
|
|
30
|
+
}
|
|
31
|
+
return { type, key: key === undefined ? null : String(key), props };
|
|
32
|
+
}
|
|
33
|
+
export function cloneElement(element: any, config?: any, ...children: any[]) {
|
|
34
|
+
const cloned = createElement(element.type, { ...element.props, ...config }, ...children);
|
|
35
|
+
cloned.key = config?.key === undefined ? element.key : cloned.key;
|
|
36
|
+
return cloned;
|
|
37
|
+
}
|
|
23
38
|
|
|
24
|
-
|
|
39
|
+
const noop = (..._args: any[]) => {};
|
|
40
|
+
export const createContext = (defaultValue: any) => ({
|
|
25
41
|
Provider: 'react.provider',
|
|
26
42
|
Consumer: 'react.consumer',
|
|
27
43
|
_currentValue: defaultValue,
|
|
28
44
|
});
|
|
45
|
+
export function useContext(context: any) {
|
|
46
|
+
return context._currentValue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function useState(initialState?: any) {
|
|
50
|
+
return [typeof initialState === 'function' ? initialState() : initialState, noop];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function useReducer(_reducer: any, initialArg: any, init?: any) {
|
|
54
|
+
return [init ? init(initialArg) : initialArg, noop];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const useRef = (initialValue: any) => ({ current: initialValue });
|
|
58
|
+
export const useMemo = (factory: any, _deps?: any) => factory();
|
|
59
|
+
export const useCallback = (callback: any, _deps?: any) => callback;
|
|
60
|
+
export const useEffectEvent = (callback: any) => callback;
|
|
61
|
+
|
|
62
|
+
export const useEffect = noop;
|
|
63
|
+
export const useLayoutEffect = noop;
|
|
64
|
+
export const useInsertionEffect = noop;
|
|
65
|
+
export const useImperativeHandle = noop;
|
|
66
|
+
export const useDebugValue = noop;
|
|
67
|
+
|
|
68
|
+
export const useDeferredValue = (value: any, _initialValue?: any) => value;
|
|
69
|
+
export const startTransition = (callback: any) => {
|
|
70
|
+
callback();
|
|
71
|
+
};
|
|
72
|
+
export const useTransition = (): any[] => [false, startTransition];
|
|
73
|
+
let nextId = 0;
|
|
74
|
+
export const useId = () => `:expo-widget-${nextId++}:`;
|
|
75
|
+
|
|
76
|
+
export const useSyncExternalStore = (_subscribe: any, getSnapshot: any, getServerSnapshot?: any) =>
|
|
77
|
+
(getServerSnapshot ?? getSnapshot)();
|
|
78
|
+
|
|
79
|
+
export const useOptimistic = (state: any, _reducer?: any) => [state, noop];
|
|
80
|
+
export const useActionState = (_action: any, initialState: any, _permalink?: any) => [
|
|
81
|
+
initialState,
|
|
82
|
+
noop,
|
|
83
|
+
false,
|
|
84
|
+
];
|
|
29
85
|
|
|
30
|
-
export
|
|
86
|
+
export function use(resource: any) {
|
|
87
|
+
if ('_currentValue' in resource) {
|
|
88
|
+
return resource._currentValue;
|
|
89
|
+
}
|
|
90
|
+
return resource.status === 'fulfilled' ? resource.value : undefined;
|
|
91
|
+
}
|
package/expo-module.config.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"modules": ["expo.modules.widgets.WidgetsModule"],
|
|
8
8
|
"gradlePlugins": [
|
|
9
9
|
{
|
|
10
|
-
"id": "io.github.
|
|
11
|
-
"group": "io.github.
|
|
12
|
-
"version": "0.3.
|
|
10
|
+
"id": "io.github.expo.peek.glance-fork",
|
|
11
|
+
"group": "io.github.expo.peek",
|
|
12
|
+
"version": "0.3.1"
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
15
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import ExpoModulesCore
|
|
3
|
+
import ExpoUI
|
|
4
|
+
#if !os(tvOS)
|
|
5
|
+
import WidgetKit
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
public final class AccessoryWidgetBackgroundProps: UIBaseViewProps {}
|
|
9
|
+
|
|
10
|
+
public struct AccessoryWidgetBackgroundView: ExpoSwiftUI.View {
|
|
11
|
+
@ObservedObject public var props: AccessoryWidgetBackgroundProps
|
|
12
|
+
|
|
13
|
+
public init(props: AccessoryWidgetBackgroundProps) {
|
|
14
|
+
self.props = props
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public var body: some View {
|
|
18
|
+
#if !os(tvOS)
|
|
19
|
+
if #available(iOS 16.0, *) {
|
|
20
|
+
AccessoryWidgetBackground()
|
|
21
|
+
} else {
|
|
22
|
+
Color.clear
|
|
23
|
+
}
|
|
24
|
+
#else
|
|
25
|
+
EmptyView()
|
|
26
|
+
#endif
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import ExpoModulesCore
|
|
4
|
+
import ExpoUI
|
|
5
|
+
import SwiftUI
|
|
6
|
+
#if !os(tvOS)
|
|
7
|
+
import WidgetKit
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
internal enum WidgetAccentedRenderingModeOptions: String, Enumerable {
|
|
11
|
+
case accented
|
|
12
|
+
case desaturated
|
|
13
|
+
case accentedDesaturated
|
|
14
|
+
case fullColor
|
|
15
|
+
|
|
16
|
+
#if !os(tvOS)
|
|
17
|
+
@available(iOS 18.0, macOS 15.0, *)
|
|
18
|
+
var toWidgetAccentedRenderingMode: WidgetAccentedRenderingMode {
|
|
19
|
+
switch self {
|
|
20
|
+
case .accented: return .accented
|
|
21
|
+
case .accentedDesaturated: return .accentedDesaturated
|
|
22
|
+
case .desaturated: return .desaturated
|
|
23
|
+
case .fullColor: return .fullColor
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
#endif
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* This is a unique modifier that exists only on Image, but returns some View, and for this reason it cannot be a ViewModifier.
|
|
31
|
+
*/
|
|
32
|
+
internal struct WidgetAccentedRenderingModeModifier: Record {
|
|
33
|
+
@Field var renderingMode: WidgetAccentedRenderingModeOptions?
|
|
34
|
+
|
|
35
|
+
@ViewBuilder
|
|
36
|
+
func apply(to image: Image) -> some View {
|
|
37
|
+
#if !os(tvOS)
|
|
38
|
+
if #available(iOS 18.0, macOS 15.0, *), renderingMode != nil {
|
|
39
|
+
image.widgetAccentedRenderingMode(renderingMode?.toWidgetAccentedRenderingMode)
|
|
40
|
+
} else {
|
|
41
|
+
image
|
|
42
|
+
}
|
|
43
|
+
#else
|
|
44
|
+
image
|
|
45
|
+
#endif
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
internal struct WidgetURLModifier: ViewModifier, Record {
|
|
50
|
+
@Field var url: URL?
|
|
51
|
+
|
|
52
|
+
func body(content: Content) -> some View {
|
|
53
|
+
#if !os(tvOS)
|
|
54
|
+
content.widgetURL(url)
|
|
55
|
+
#else
|
|
56
|
+
content
|
|
57
|
+
#endif
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
internal struct ActivityBackgroundTintModifier: ViewModifier, Record {
|
|
62
|
+
@Field var color: Color?
|
|
63
|
+
|
|
64
|
+
func body(content: Content) -> some View {
|
|
65
|
+
#if !os(tvOS) && !os(macOS) && !targetEnvironment(macCatalyst)
|
|
66
|
+
content.activityBackgroundTint(color)
|
|
67
|
+
#else
|
|
68
|
+
content
|
|
69
|
+
#endif
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Registers the modifiers that need WidgetKit. They live here rather than in ExpoUI,
|
|
75
|
+
* so apps that use ExpoUI without widgets do not link WidgetKit.
|
|
76
|
+
* See: https://github.com/expo/expo/issues/50777
|
|
77
|
+
*/
|
|
78
|
+
internal func registerWidgetModifiers() {
|
|
79
|
+
ViewModifierRegistry.register("widgetURL") { params, appContext, _ in
|
|
80
|
+
return try WidgetURLModifier(from: params, appContext: appContext)
|
|
81
|
+
}
|
|
82
|
+
ViewModifierRegistry.register("activityBackgroundTint") { params, appContext, _ in
|
|
83
|
+
return try ActivityBackgroundTintModifier(from: params, appContext: appContext)
|
|
84
|
+
}
|
|
85
|
+
ViewModifierRegistry.widgetKit = WidgetKitModifiersImpl()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private struct WidgetKitModifiersImpl: WidgetKitModifiers {
|
|
89
|
+
func containerBackground(_ view: AnyView, style: AnyShapeStyle) -> AnyView {
|
|
90
|
+
guard #available(iOS 17.0, *) else {
|
|
91
|
+
return view
|
|
92
|
+
}
|
|
93
|
+
return AnyView(view.containerBackground(style, for: .widget))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func widgetAccentedRenderingMode(_ image: Image, params: [String: Any], appContext: AppContext) -> AnyView? {
|
|
97
|
+
guard #available(iOS 18.0, *), let modifier = try? WidgetAccentedRenderingModeModifier(from: params, appContext: appContext) else {
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
return AnyView(modifier.apply(to: image))
|
|
101
|
+
}
|
|
102
|
+
}
|
package/ios/WidgetsContext.swift
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-widgets",
|
|
3
|
-
"version": "58.0.
|
|
3
|
+
"version": "58.0.10",
|
|
4
4
|
"description": "Widgets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"expo",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@expo/plist": "^0.10.1",
|
|
31
|
-
"@expo/ui": "~58.0.
|
|
31
|
+
"@expo/ui": "~58.0.10"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@expo/spawn-async": "^1.8.0",
|
|
35
35
|
"@types/jest": "^29.2.1",
|
|
36
36
|
"@types/node": "^22.14.0",
|
|
37
37
|
"@types/react": "~19.3.0",
|
|
38
|
-
"expo": "58.0.
|
|
38
|
+
"expo": "58.0.1",
|
|
39
39
|
"expo-module-scripts": "56.0.4",
|
|
40
40
|
"react-native": "0.88.0-rc.3",
|
|
41
41
|
"resolve-workspace-root": "^2.0.0"
|