@react-native-oh/react-native-harmony 0.72.14-lazy → 0.72.17

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.
@@ -41,7 +41,7 @@ class Alert {
41
41
  }
42
42
 
43
43
  // At most two buttons. Ignore rest.
44
- const validButtons: Buttons = buttons.slice(0, 2);
44
+ const validButtons: Buttons = (buttons ?? [{text: "OK"}]).slice(0, 2)
45
45
  const secondaryButton = validButtons.pop();
46
46
  const primaryButton = validButtons.pop();
47
47
 
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ // RNOH: patch
12
+ // COPIED FROM: https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js
13
+
14
+ import type { HostComponent } from "react-native/Libraries/Renderer/shims/ReactNativeTypes";
15
+ import type { EventSubscription } from "react-native/Libraries/vendor/emitter/EventEmitter";
16
+ import type { ElementRef } from "react";
17
+
18
+ // RNOH: patch - imports fixed
19
+ import RCTDeviceEventEmitter from "react-native/Libraries/EventEmitter/RCTDeviceEventEmitter";
20
+ import { sendAccessibilityEvent } from "react-native/Libraries/ReactNative/RendererProxy";
21
+ import Platform from "../../Utilities/Platform";
22
+ import legacySendAccessibilityEvent from "react-native/Libraries/Components/AccessibilityInfo/legacySendAccessibilityEvent";
23
+ import NativeAccessibilityInfoAndroid from "react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo";
24
+ import NativeAccessibilityManagerIOS from "react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager";
25
+
26
+ // Events that are only supported on Android.
27
+ type AccessibilityEventDefinitionsAndroid = {
28
+ accessibilityServiceChanged: [boolean],
29
+ };
30
+
31
+ // Events that are only supported on iOS.
32
+ type AccessibilityEventDefinitionsIOS = {
33
+ announcementFinished: [{ announcement: string, success: boolean }],
34
+ boldTextChanged: [boolean],
35
+ grayscaleChanged: [boolean],
36
+ invertColorsChanged: [boolean],
37
+ reduceTransparencyChanged: [boolean],
38
+ };
39
+
40
+ type AccessibilityEventDefinitions = {
41
+ ...AccessibilityEventDefinitionsAndroid,
42
+ ...AccessibilityEventDefinitionsIOS,
43
+ change: [boolean], // screenReaderChanged
44
+ reduceMotionChanged: [boolean],
45
+ screenReaderChanged: [boolean],
46
+ };
47
+
48
+ type AccessibilityEventTypes = "click" | "focus" | "viewHoverEnter";
49
+
50
+ // Mapping of public event names to platform-specific event names.
51
+ const EventNames: Map<
52
+ $Keys<AccessibilityEventDefinitions>,
53
+ string
54
+ > = Platform.OS === "android"
55
+ ? new Map([
56
+ ["change", "touchExplorationDidChange"],
57
+ ["reduceMotionChanged", "reduceMotionDidChange"],
58
+ ["screenReaderChanged", "touchExplorationDidChange"],
59
+ ["accessibilityServiceChanged", "accessibilityServiceDidChange"],
60
+ ])
61
+ : new Map([
62
+ ["announcementFinished", "announcementFinished"],
63
+ ["boldTextChanged", "boldTextChanged"],
64
+ ["change", "screenReaderChanged"],
65
+ ["grayscaleChanged", "grayscaleChanged"],
66
+ ["invertColorsChanged", "invertColorsChanged"],
67
+ ["reduceMotionChanged", "reduceMotionChanged"],
68
+ ["reduceTransparencyChanged", "reduceTransparencyChanged"],
69
+ ["screenReaderChanged", "screenReaderChanged"],
70
+ ]);
71
+
72
+ /**
73
+ * Sometimes it's useful to know whether or not the device has a screen reader
74
+ * that is currently active. The `AccessibilityInfo` API is designed for this
75
+ * purpose. You can use it to query the current state of the screen reader as
76
+ * well as to register to be notified when the state of the screen reader
77
+ * changes.
78
+ *
79
+ * See https://reactnative.dev/docs/accessibilityinfo
80
+ */
81
+ const AccessibilityInfo = {
82
+ /**
83
+ * Query whether bold text is currently enabled.
84
+ *
85
+ * Returns a promise which resolves to a boolean.
86
+ * The result is `true` when bold text is enabled and `false` otherwise.
87
+ *
88
+ * See https://reactnative.dev/docs/accessibilityinfo#isBoldTextEnabled
89
+ */
90
+ isBoldTextEnabled(): Promise<boolean> {
91
+ if (Platform.OS === "android") {
92
+ return Promise.resolve(false);
93
+ } else {
94
+ return new Promise((resolve, reject) => {
95
+ if (NativeAccessibilityManagerIOS != null) {
96
+ NativeAccessibilityManagerIOS.getCurrentBoldTextState(
97
+ resolve,
98
+ reject
99
+ );
100
+ } else {
101
+ reject(null);
102
+ }
103
+ });
104
+ }
105
+ },
106
+
107
+ /**
108
+ * Query whether grayscale is currently enabled.
109
+ *
110
+ * Returns a promise which resolves to a boolean.
111
+ * The result is `true` when grayscale is enabled and `false` otherwise.
112
+ *
113
+ * See https://reactnative.dev/docs/accessibilityinfo#isGrayscaleEnabled
114
+ */
115
+ isGrayscaleEnabled(): Promise<boolean> {
116
+ if (Platform.OS === "android") {
117
+ return Promise.resolve(false);
118
+ } else {
119
+ return new Promise((resolve, reject) => {
120
+ if (NativeAccessibilityManagerIOS != null) {
121
+ NativeAccessibilityManagerIOS.getCurrentGrayscaleState(
122
+ resolve,
123
+ reject
124
+ );
125
+ } else {
126
+ reject(null);
127
+ }
128
+ });
129
+ }
130
+ },
131
+
132
+ /**
133
+ * Query whether inverted colors are currently enabled.
134
+ *
135
+ * Returns a promise which resolves to a boolean.
136
+ * The result is `true` when invert color is enabled and `false` otherwise.
137
+ *
138
+ * See https://reactnative.dev/docs/accessibilityinfo#isInvertColorsEnabled
139
+ */
140
+ isInvertColorsEnabled(): Promise<boolean> {
141
+ if (Platform.OS === "android") {
142
+ return Promise.resolve(false);
143
+ } else {
144
+ return new Promise((resolve, reject) => {
145
+ if (NativeAccessibilityManagerIOS != null) {
146
+ NativeAccessibilityManagerIOS.getCurrentInvertColorsState(
147
+ resolve,
148
+ reject
149
+ );
150
+ } else {
151
+ reject(null);
152
+ }
153
+ });
154
+ }
155
+ },
156
+
157
+ /**
158
+ * Query whether reduced motion is currently enabled.
159
+ *
160
+ * Returns a promise which resolves to a boolean.
161
+ * The result is `true` when a reduce motion is enabled and `false` otherwise.
162
+ *
163
+ * See https://reactnative.dev/docs/accessibilityinfo#isReduceMotionEnabled
164
+ */
165
+ isReduceMotionEnabled(): Promise<boolean> {
166
+ return new Promise((resolve, reject) => {
167
+ if (Platform.OS === "android") {
168
+ if (NativeAccessibilityInfoAndroid != null) {
169
+ NativeAccessibilityInfoAndroid.isReduceMotionEnabled(resolve);
170
+ } else {
171
+ reject(null);
172
+ }
173
+ } else {
174
+ if (NativeAccessibilityManagerIOS != null) {
175
+ NativeAccessibilityManagerIOS.getCurrentReduceMotionState(
176
+ resolve,
177
+ reject
178
+ );
179
+ } else {
180
+ reject(null);
181
+ }
182
+ }
183
+ });
184
+ },
185
+
186
+ /**
187
+ * Query whether reduce motion and prefer cross-fade transitions settings are currently enabled.
188
+ *
189
+ * Returns a promise which resolves to a boolean.
190
+ * The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise.
191
+ *
192
+ * See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions
193
+ */
194
+ prefersCrossFadeTransitions(): Promise<boolean> {
195
+ return new Promise((resolve, reject) => {
196
+ if (Platform.OS === "android") {
197
+ return Promise.resolve(false);
198
+ } else {
199
+ if (
200
+ NativeAccessibilityManagerIOS?.getCurrentPrefersCrossFadeTransitionsState !=
201
+ null
202
+ ) {
203
+ NativeAccessibilityManagerIOS.getCurrentPrefersCrossFadeTransitionsState(
204
+ resolve,
205
+ reject
206
+ );
207
+ } else {
208
+ reject(null);
209
+ }
210
+ }
211
+ });
212
+ },
213
+
214
+ /**
215
+ * Query whether reduced transparency is currently enabled.
216
+ *
217
+ * Returns a promise which resolves to a boolean.
218
+ * The result is `true` when a reduce transparency is enabled and `false` otherwise.
219
+ *
220
+ * See https://reactnative.dev/docs/accessibilityinfo#isReduceTransparencyEnabled
221
+ */
222
+ isReduceTransparencyEnabled(): Promise<boolean> {
223
+ if (Platform.OS === "android") {
224
+ return Promise.resolve(false);
225
+ } else {
226
+ return new Promise((resolve, reject) => {
227
+ if (NativeAccessibilityManagerIOS != null) {
228
+ NativeAccessibilityManagerIOS.getCurrentReduceTransparencyState(
229
+ resolve,
230
+ reject
231
+ );
232
+ } else {
233
+ reject(null);
234
+ }
235
+ });
236
+ }
237
+ },
238
+
239
+ /**
240
+ * Query whether a screen reader is currently enabled.
241
+ *
242
+ * Returns a promise which resolves to a boolean.
243
+ * The result is `true` when a screen reader is enabled and `false` otherwise.
244
+ *
245
+ * See https://reactnative.dev/docs/accessibilityinfo#isScreenReaderEnabled
246
+ */
247
+ isScreenReaderEnabled(): Promise<boolean> {
248
+ return new Promise((resolve, reject) => {
249
+ // RNOH: path to support open harmony
250
+ if (Platform.OS === "android" || Platform.OS === "harmony") {
251
+ if (NativeAccessibilityInfoAndroid != null) {
252
+ NativeAccessibilityInfoAndroid.isTouchExplorationEnabled(resolve);
253
+ } else {
254
+ reject(null);
255
+ }
256
+ } else {
257
+ if (NativeAccessibilityManagerIOS != null) {
258
+ NativeAccessibilityManagerIOS.getCurrentVoiceOverState(
259
+ resolve,
260
+ reject
261
+ );
262
+ } else {
263
+ reject(null);
264
+ }
265
+ }
266
+ });
267
+ },
268
+
269
+ /**
270
+ * Query whether Accessibility Service is currently enabled.
271
+ *
272
+ * Returns a promise which resolves to a boolean.
273
+ * The result is `true` when any service is enabled and `false` otherwise.
274
+ *
275
+ * @platform android
276
+ *
277
+ * See https://reactnative.dev/docs/accessibilityinfo/#isaccessibilityserviceenabled-android
278
+ */
279
+ isAccessibilityServiceEnabled(): Promise<boolean> {
280
+ return new Promise((resolve, reject) => {
281
+ if (Platform.OS === "android") {
282
+ if (
283
+ NativeAccessibilityInfoAndroid != null &&
284
+ NativeAccessibilityInfoAndroid.isAccessibilityServiceEnabled != null
285
+ ) {
286
+ NativeAccessibilityInfoAndroid.isAccessibilityServiceEnabled(resolve);
287
+ } else {
288
+ reject(null);
289
+ }
290
+ } else {
291
+ reject(null);
292
+ }
293
+ });
294
+ },
295
+
296
+ /**
297
+ * Add an event handler. Supported events:
298
+ *
299
+ * - `reduceMotionChanged`: Fires when the state of the reduce motion toggle changes.
300
+ * The argument to the event handler is a boolean. The boolean is `true` when a reduce
301
+ * motion is enabled (or when "Transition Animation Scale" in "Developer options" is
302
+ * "Animation off") and `false` otherwise.
303
+ * - `screenReaderChanged`: Fires when the state of the screen reader changes. The argument
304
+ * to the event handler is a boolean. The boolean is `true` when a screen
305
+ * reader is enabled and `false` otherwise.
306
+ *
307
+ * These events are only supported on iOS:
308
+ *
309
+ * - `boldTextChanged`: iOS-only event. Fires when the state of the bold text toggle changes.
310
+ * The argument to the event handler is a boolean. The boolean is `true` when a bold text
311
+ * is enabled and `false` otherwise.
312
+ * - `grayscaleChanged`: iOS-only event. Fires when the state of the gray scale toggle changes.
313
+ * The argument to the event handler is a boolean. The boolean is `true` when a gray scale
314
+ * is enabled and `false` otherwise.
315
+ * - `invertColorsChanged`: iOS-only event. Fires when the state of the invert colors toggle
316
+ * changes. The argument to the event handler is a boolean. The boolean is `true` when a invert
317
+ * colors is enabled and `false` otherwise.
318
+ * - `reduceTransparencyChanged`: iOS-only event. Fires when the state of the reduce transparency
319
+ * toggle changes. The argument to the event handler is a boolean. The boolean is `true`
320
+ * when a reduce transparency is enabled and `false` otherwise.
321
+ * - `announcementFinished`: iOS-only event. Fires when the screen reader has
322
+ * finished making an announcement. The argument to the event handler is a
323
+ * dictionary with these keys:
324
+ * - `announcement`: The string announced by the screen reader.
325
+ * - `success`: A boolean indicating whether the announcement was
326
+ * successfully made.
327
+ *
328
+ * See https://reactnative.dev/docs/accessibilityinfo#addeventlistener
329
+ */
330
+ addEventListener<K: $Keys<AccessibilityEventDefinitions>>(
331
+ eventName: K,
332
+ // $FlowIssue[incompatible-type] - Flow bug with unions and generics (T128099423)
333
+ handler: (...$ElementType<AccessibilityEventDefinitions, K>) => void
334
+ ): EventSubscription {
335
+ const deviceEventName = EventNames.get(eventName);
336
+ return deviceEventName == null
337
+ ? { remove(): void {} }
338
+ : // $FlowFixMe[incompatible-call]
339
+ RCTDeviceEventEmitter.addListener(deviceEventName, handler);
340
+ },
341
+
342
+ /**
343
+ * Set accessibility focus to a React component.
344
+ *
345
+ * See https://reactnative.dev/docs/accessibilityinfo#setaccessibilityfocus
346
+ */
347
+ setAccessibilityFocus(reactTag: number): void {
348
+ legacySendAccessibilityEvent(reactTag, "focus");
349
+ },
350
+
351
+ /**
352
+ * Send a named accessibility event to a HostComponent.
353
+ */
354
+ sendAccessibilityEvent(
355
+ handle: ElementRef<HostComponent<mixed>>,
356
+ eventType: AccessibilityEventTypes
357
+ ) {
358
+ // iOS only supports 'focus' event types
359
+ if (Platform.OS === "ios" && eventType === "click") {
360
+ return;
361
+ }
362
+ // route through React renderer to distinguish between Fabric and non-Fabric handles
363
+ sendAccessibilityEvent(handle, eventType);
364
+ },
365
+
366
+ /**
367
+ * Post a string to be announced by the screen reader.
368
+ *
369
+ * See https://reactnative.dev/docs/accessibilityinfo#announceforaccessibility
370
+ */
371
+ announceForAccessibility(announcement: string): void {
372
+ if (Platform.OS === "android") {
373
+ NativeAccessibilityInfoAndroid?.announceForAccessibility(announcement);
374
+ } else {
375
+ NativeAccessibilityManagerIOS?.announceForAccessibility(announcement);
376
+ }
377
+ },
378
+
379
+ /**
380
+ * Post a string to be announced by the screen reader.
381
+ * - `announcement`: The string announced by the screen reader.
382
+ * - `options`: An object that configures the reading options.
383
+ * - `queue`: The announcement will be queued behind existing announcements. iOS only.
384
+ */
385
+ announceForAccessibilityWithOptions(
386
+ announcement: string,
387
+ options: { queue?: boolean }
388
+ ): void {
389
+ if (Platform.OS === "android") {
390
+ NativeAccessibilityInfoAndroid?.announceForAccessibility(announcement);
391
+ } else {
392
+ if (NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions) {
393
+ NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions(
394
+ announcement,
395
+ options
396
+ );
397
+ } else {
398
+ NativeAccessibilityManagerIOS?.announceForAccessibility(announcement);
399
+ }
400
+ }
401
+ },
402
+
403
+ /**
404
+ * Get the recommended timeout for changes to the UI needed by this user.
405
+ *
406
+ * See https://reactnative.dev/docs/accessibilityinfo#getrecommendedtimeoutmillis
407
+ */
408
+ getRecommendedTimeoutMillis(originalTimeout: number): Promise<number> {
409
+ if (Platform.OS === "android") {
410
+ return new Promise((resolve, reject) => {
411
+ if (NativeAccessibilityInfoAndroid?.getRecommendedTimeoutMillis) {
412
+ NativeAccessibilityInfoAndroid.getRecommendedTimeoutMillis(
413
+ originalTimeout,
414
+ resolve
415
+ );
416
+ } else {
417
+ resolve(originalTimeout);
418
+ }
419
+ });
420
+ } else {
421
+ return Promise.resolve(originalTimeout);
422
+ }
423
+ },
424
+ };
425
+
426
+ export default AccessibilityInfo;
@@ -1316,7 +1316,8 @@ class ScrollView extends React.Component<Props, State> {
1316
1316
  FrameRateLogger.beginScroll(); // TODO: track all scrolls after implementing onScrollEndAnimation
1317
1317
 
1318
1318
  if (
1319
- Platform.OS === "android" &&
1319
+ // RNOH: patch - add support for OpenHarmony
1320
+ (Platform.OS === "android" || Platform.OS === "harmony") &&
1320
1321
  this.props.keyboardDismissMode === "on-drag"
1321
1322
  ) {
1322
1323
  dismissKeyboard();
@@ -1809,10 +1810,10 @@ class ScrollView extends React.Component<Props, State> {
1809
1810
  // default to true
1810
1811
  snapToEnd: this.props.snapToEnd !== false,
1811
1812
  // pagingEnabled is overridden by snapToInterval / snapToOffsets
1812
- pagingEnabled:
1813
- this.props.pagingEnabled === true &&
1814
- this.props.snapToInterval == null &&
1815
- this.props.snapToOffsets == null,
1813
+ pagingEnabled:
1814
+ this.props.pagingEnabled === true &&
1815
+ this.props.snapToInterval == null &&
1816
+ this.props.snapToOffsets == null,
1816
1817
  };
1817
1818
 
1818
1819
  const { decelerationRate } = this.props;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @format
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ if (__DEV__) {
14
+ let isWebSocketOpen = false;
15
+ let ws = null;
16
+
17
+ const reactDevTools = require('react-devtools-core');
18
+ const connectToDevTools = () => {
19
+ if (ws !== null && isWebSocketOpen) {
20
+ // If the DevTools backend is already connected, don't recreate the WebSocket.
21
+ // This would break the connection.
22
+ // If there isn't an active connection, a backend may be waiting to connect,
23
+ // in which case it's okay to make a new one.
24
+ return;
25
+ }
26
+
27
+ // not when debugging in chrome
28
+ // TODO(t12832058) This check is broken
29
+ if (!window.document) {
30
+ const AppState = require('react-native/Libraries/AppState/AppState');
31
+ const getDevServer = require('react-native/Libraries/Core/Devtools/getDevServer');
32
+
33
+ // Don't steal the DevTools from currently active app.
34
+ // Note: if you add any AppState subscriptions to this file,
35
+ // you will also need to guard against `AppState.isAvailable`,
36
+ // or the code will throw for bundles that don't have it.
37
+ const isAppActive = () => AppState.currentState !== 'background';
38
+
39
+ // RNOH patch: wait until appstate is active before connecting
40
+ if (!isAppActive()) {
41
+ const subscription = AppState.addEventListener('change', () => {
42
+ if (isAppActive()) {
43
+ connectToDevTools();
44
+ subscription.remove();
45
+ }
46
+ });
47
+ return;
48
+ }
49
+
50
+ // Get hostname from development server (packager)
51
+ const devServer = getDevServer();
52
+ const host = devServer.bundleLoadedFromServer
53
+ ? devServer.url
54
+ .replace(/https?:\/\//, '')
55
+ .replace(/\/$/, '')
56
+ .split(':')[0]
57
+ : 'localhost';
58
+
59
+ // Read the optional global variable for backward compatibility.
60
+ // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0.
61
+ const port =
62
+ window.__REACT_DEVTOOLS_PORT__ != null
63
+ ? window.__REACT_DEVTOOLS_PORT__
64
+ : 8097;
65
+
66
+ const WebSocket = require('react-native/Libraries/WebSocket/WebSocket');
67
+ ws = new WebSocket('ws://' + host + ':' + port);
68
+ ws.addEventListener('close', event => {
69
+ isWebSocketOpen = false;
70
+ });
71
+ ws.addEventListener('open', event => {
72
+ isWebSocketOpen = true;
73
+ });
74
+
75
+ const ReactNativeStyleAttributes = require('react-native/Libraries/Components/View/ReactNativeStyleAttributes');
76
+ const devToolsSettingsManager = require('react-native/Libraries/DevToolsSettings/DevToolsSettingsManager');
77
+
78
+ reactDevTools.connectToDevTools({
79
+ isAppActive,
80
+ resolveRNStyle: require('react-native/Libraries/StyleSheet/flattenStyle'),
81
+ nativeStyleEditorValidAttributes: Object.keys(
82
+ ReactNativeStyleAttributes,
83
+ ),
84
+ websocket: ws,
85
+ devToolsSettingsManager,
86
+ });
87
+ }
88
+ };
89
+
90
+ const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
91
+ RCTNativeAppEventEmitter.addListener('RCTDevMenuShown', connectToDevTools);
92
+ connectToDevTools(); // Try connecting once on load
93
+ }
@@ -2,6 +2,10 @@ import {
2
2
  getAssetDestRelativePath,
3
3
  Asset,
4
4
  } from '@react-native-oh/react-native-harmony-cli/src/assetResolver';
5
+ import {
6
+ getBasePath,
7
+ } from '@react-native/assets-registry/path-support';
8
+ import { Platform } from 'react-native';
5
9
 
6
10
  type ResolvedAssetSource = {
7
11
  readonly __packager_asset: boolean;
@@ -11,6 +15,11 @@ type ResolvedAssetSource = {
11
15
  readonly scale: number;
12
16
  };
13
17
 
18
+ function getAssetPath(asset: Asset): string {
19
+ const assetDir = getBasePath(asset);
20
+ return assetDir + '/' + asset.name + '.' + asset.type;
21
+ }
22
+
14
23
  class AssetSourceResolver {
15
24
  constructor(
16
25
  private serverUrl: string | undefined,
@@ -18,7 +27,15 @@ class AssetSourceResolver {
18
27
  private asset: Asset
19
28
  ) {}
20
29
 
30
+ isLoadedFromServer(): boolean {
31
+ return !!this.serverUrl;
32
+ }
33
+
21
34
  public defaultAsset(): ResolvedAssetSource {
35
+ if (this.isLoadedFromServer()) {
36
+ return this.assetServerURL();
37
+ }
38
+
22
39
  return {
23
40
  __packager_asset: this.asset.__packager_asset,
24
41
  uri: `asset://${getAssetDestRelativePath(this.asset)}`,
@@ -27,6 +44,35 @@ class AssetSourceResolver {
27
44
  height: this.asset.height,
28
45
  };
29
46
  }
47
+
48
+ /**
49
+ * Returns an absolute URL which can be used to fetch the asset
50
+ * from the devserver
51
+ */
52
+ assetServerURL(): ResolvedAssetSource {
53
+ if (!this.serverUrl) {
54
+ throw new Error('need server to load from');
55
+ }
56
+
57
+ return this.fromSource(
58
+ this.serverUrl +
59
+ getAssetPath(this.asset) +
60
+ '?platform=' +
61
+ Platform.OS +
62
+ '&hash=' +
63
+ this.asset.hash,
64
+ );
65
+ }
66
+
67
+ fromSource(source: string): ResolvedAssetSource {
68
+ return {
69
+ __packager_asset: true,
70
+ width: this.asset.width,
71
+ height: this.asset.height,
72
+ uri: source,
73
+ scale: 1,
74
+ };
75
+ }
30
76
  }
31
77
 
32
78
  module.exports = AssetSourceResolver;
@@ -23,6 +23,18 @@ const bubblingEventTypes = {
23
23
  bubbled: 'onChange',
24
24
  },
25
25
  },
26
+ topFocus: {
27
+ phasedRegistrationNames: {
28
+ bubbled: 'onFocus',
29
+ captured: 'onFocusCapture',
30
+ },
31
+ },
32
+ topBlur: {
33
+ phasedRegistrationNames: {
34
+ bubbled: 'onBlur',
35
+ captured: 'onBlurCapture',
36
+ },
37
+ },
26
38
  topSelect: {
27
39
  phasedRegistrationNames: {
28
40
  captured: 'onSelectCapture',