Skip to content

Commit

Permalink
Add forked Dimensions.win32 module implementation (#10475)
Browse files Browse the repository at this point in the history
* Add forked Dimensions.win32 module implementation

* Change files

* Remove unimplemented values and add error

* Add back zeros for unimplemented values

* Remove errors and redefine unimplemented values

* Alphabetize RN Tester list

* Update comment for Dimensions

Co-authored-by: Krystal Kramer <krsiler@microsoft.com>
  • Loading branch information
PPatBoyd and ksiler committed Sep 14, 2022
1 parent d076e36 commit fcec4fe
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add Dimensions.win32 implementation to support text scale factor",
"packageName": "@office-iss/react-native-win32",
"email": "patboyd@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
import type {RNTesterModuleInfo} from '../types/RNTesterTypes';

const Components: Array<RNTesterModuleInfo> = [
{
key: 'AccessibilityExampleWin32',
module: require('../examples-win32/Accessibility/AccessibilityExampleWin32'),
},
{
key: 'ActivityIndicatorExample',
category: 'UI',
Expand All @@ -24,8 +28,13 @@ const Components: Array<RNTesterModuleInfo> = [
module: require('../examples/Button/ButtonExample'),
},
{
key: 'AccessibilityExampleWin32',
module: require('../examples-win32/Accessibility/AccessibilityExampleWin32'),
key: 'ColorGradientWin32Example',
module: require('../examples-win32/Color/ColorGradientWin32Example'),
},
{
key: 'Dimensions',
category: 'UI',
module: require('../examples/Dimensions/DimensionsExample'),
},
/*
{
Expand All @@ -39,6 +48,12 @@ const Components: Array<RNTesterModuleInfo> = [
category: 'Basic',
module: require('../examples/Image/ImageExample'),
},
*/
{
key: 'ImageWin32Test',
module: require('@office-iss/react-native-win32/Libraries/Image/Tests/ImageWin32Test'),
},
/*
{
key: 'JSResponderHandlerExample',
module: require('../examples/JSResponderHandlerExample/JSResponderHandlerExample'),
Expand All @@ -56,6 +71,11 @@ const Components: Array<RNTesterModuleInfo> = [
key: 'NewAppScreenExample',
module: require('../examples/NewAppScreen/NewAppScreenExample'),
},
{
key: 'NewArchitectureExample',
category: 'UI',
module: require('../examples/NewArchitecture/NewArchitectureExample'),
},
*/
{
key: 'PressableExample',
Expand Down Expand Up @@ -90,6 +110,15 @@ const Components: Array<RNTesterModuleInfo> = [
key: 'TextInputs with key prop',
module: require('../examples/TextInput/TextInputKeyProp'),
},
{
key: 'TextInputExample',
category: 'Basic',
module: require('@office-iss/react-native-win32/Libraries/Components/TextInput/Tests/TextInputTest'),
},
{
key: 'TextWin32Test',
module: require('@office-iss/react-native-win32/Libraries/Components/Text/Tests/TextWin32Test'),
},
{
key: 'TouchableExample',
category: 'UI',
Expand All @@ -104,32 +133,10 @@ const Components: Array<RNTesterModuleInfo> = [
category: 'Basic',
module: require('../examples/View/ViewExample'),
},
//{
// key: 'NewArchitectureExample',
// category: 'UI',
// module: require('../examples/NewArchitecture/NewArchitectureExample'),
//},
{
key: 'ViewWin32Test',
module: require('@office-iss/react-native-win32/Libraries/Components/View/Tests/ViewWin32Test'),
},
{
key: 'TextWin32Test',
module: require('@office-iss/react-native-win32/Libraries/Components/Text/Tests/TextWin32Test'),
},
{
key: 'TextInputExample',
category: 'Basic',
module: require('@office-iss/react-native-win32/Libraries/Components/TextInput/Tests/TextInputTest'),
},
{
key: 'ImageWin32Test',
module: require('@office-iss/react-native-win32/Libraries/Image/Tests/ImageWin32Test'),
},
{
key: 'ColorGradientWin32Example',
module: require('../examples-win32/Color/ColorGradientWin32Example'),
},
];

const APIs: Array<RNTesterModuleInfo> = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,108 @@
* @flow
*/

import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import EventEmitter, {
type EventSubscription,
} from '../vendor/emitter/EventEmitter';
import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter';
import NativeDeviceInfo, {
type DisplayMetrics,
type DisplayMetricsAndroid,
type DimensionsPayload,
} from './NativeDeviceInfo';
import invariant from 'invariant';

const eventEmitter = new EventEmitter<{
change: [DimensionsPayload],
}>();
let dimensionsInitialized = false;
let dimensions: DimensionsPayload;

/**
* While a global Dimensions object for window and screen dimensions is too simple for Win32,
* attached to this object is also fontScale which is a system global value. We expose this value
* for large text scaling support while leaving other window dimension information undefined. These undefined
* values will cause rendering issues if used but should avoid runtime failures in JS.
*/
class Dimensions {
static get(dim: string): Object {
throw new Error(
'Having a global Dimensions object is too simplistic for Win32, so this API does not work',
);
/**
* NOTE: `useWindowDimensions` is the preferred API for React components.
*
* Initial dimensions are set before `runApplication` is called so they should
* be available before any other require's are run, but may be updated later.
*
* Note: Although dimensions are available immediately, they may change (e.g
* due to device rotation) so any rendering logic or styles that depend on
* these constants should try to call this function on every render, rather
* than caching the value (for example, using inline styles rather than
* setting a value in a `StyleSheet`).
*
* Example: `const {height, width} = Dimensions.get('window');`
*
* @param {string} dim Name of dimension as defined when calling `set`.
* @returns {DisplayMetrics? | DisplayMetricsAndroid?} Value for the dimension.
*/
static get(dim: string): DisplayMetrics | DisplayMetricsAndroid {
invariant(dimensions[dim], 'No dimension set for key ' + dim);
return dimensions[dim];
}

static set(dims: $ReadOnly<{[key: string]: any, ...}>): void {
throw new Error(
'Having a global Dimensions object is too simplistic for Win32, so this API does not work',
);
/**
* This should only be called from native code by sending the
* didUpdateDimensions event.
*
* @param {DimensionsPayload} dims Simple string-keyed object of dimensions to set
*/
static set(dims: $ReadOnly<DimensionsPayload>): void {
let {screen, window} = dims;
const {windowPhysicalPixels} = dims;
if (windowPhysicalPixels) {
window = {
width: windowPhysicalPixels.width,
height: windowPhysicalPixels.height,
scale: windowPhysicalPixels.scale,
fontScale: windowPhysicalPixels.fontScale,
};
}
const {screenPhysicalPixels} = dims;
if (screenPhysicalPixels) {
screen = {
width: screenPhysicalPixels.width,
height: screenPhysicalPixels.height,
scale: screenPhysicalPixels.scale,
fontScale: screenPhysicalPixels.fontScale,
};
} else if (screen == null) {
screen = window;
}

dimensions = {window, screen};
if (dimensionsInitialized) {
// Don't fire 'change' the first time the dimensions are set.
eventEmitter.emit('change', dimensions);
} else {
dimensionsInitialized = true;
}
}

/**
* Add an event handler. Supported events:
*
* - `change`: Fires when a property within the `Dimensions` object changes. The argument
* to the event handler is an object with `window` and `screen` properties whose values
* are the same as the return values of `Dimensions.get('window')` and
* `Dimensions.get('screen')`, respectively.
*/
static addEventListener(
type: 'change',
handler: Function,
): EventSubscription {
throw new Error(
'Having a global Dimensions object is too simplistic for Win32, so this API does not work',
invariant(
type === 'change',
'Trying to subscribe to unknown event: "%s"',
type,
);
return eventEmitter.addListener(type, handler);
}

/**
Expand All @@ -40,4 +120,21 @@ class Dimensions {
}
}

let initialDims: ?$ReadOnly<DimensionsPayload> =
global.nativeExtensions &&
global.nativeExtensions.DeviceInfo &&
global.nativeExtensions.DeviceInfo.Dimensions;
if (!initialDims) {
// Subscribe before calling getConstants to make sure we don't miss any updates in between.
RCTDeviceEventEmitter.addListener(
'didUpdateDimensions',
(update: DimensionsPayload) => {
Dimensions.set(update);
},
);
initialDims = NativeDeviceInfo.getConstants().Dimensions;
}

Dimensions.set(initialDims);

module.exports = Dimensions;

0 comments on commit fcec4fe

Please sign in to comment.