[change] Add usePlatformMethods to implement instance methods

A hook equivalent for implementing "native methods" on refs to elements backed
by function components.
This commit is contained in:
Nicolas Gallagher
2020-02-03 10:50:30 -08:00
parent 51ac083d56
commit a2cccaf528
5 changed files with 89 additions and 10 deletions

View File

@@ -77,7 +77,7 @@ const UIManager = {
measureLayout(node, relativeToNativeNode, onSuccess);
},
updateView(node, props, component /* only needed to surpress React errors in development */) {
updateView(node, props) {
for (const prop in props) {
if (!Object.prototype.hasOwnProperty.call(props, prop)) {
continue;
@@ -86,7 +86,7 @@ const UIManager = {
const value = props[prop];
switch (prop) {
case 'style': {
setValueForStyles(node, value, component._reactInternalInstance);
setValueForStyles(node, value);
break;
}
case 'class':

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) Nicolas Gallagher.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type { GenericStyleProp } from '../types';
import type { ElementRef } from 'react';
import UIManager from '../exports/UIManager';
import createDOMProps from '../modules/createDOMProps';
import { useImperativeHandle, useRef } from 'react';
export default function usePlatformMethods(
hostRef: ElementRef<any>,
ref: ElementRef<any>,
classList: Array<string>,
style: GenericStyleProp<any>
) {
const previousStyle = useRef(null);
useImperativeHandle(
ref,
() => {
return {
blur() {
UIManager.blur(hostRef.current);
},
focus() {
UIManager.focus(hostRef.current);
},
measure(callback) {
UIManager.measure(hostRef.current, callback);
},
measureLayout(relativeToNativeNode, onFail, onSuccess) {
UIManager.measureLayout(hostRef.current, relativeToNativeNode, onFail, onSuccess);
},
measureInWindow(callback) {
UIManager.measureInWindow(hostRef.current, callback);
},
setNativeProps(nativeProps) {
const node = hostRef.current;
if (node && nativeProps) {
const domProps = createDOMProps(null, {
...nativeProps,
classList: [nativeProps.className, classList],
style: [style, nativeProps.style]
});
const nextDomStyle = domProps.style;
if (previousStyle.current != null) {
if (domProps.style == null) {
domProps.style = {};
}
for (const styleName in previousStyle.current) {
if (domProps.style[styleName] == null) {
domProps.style[styleName] = '';
}
}
}
previousStyle.current = nextDomStyle;
UIManager.updateView(node, domProps);
}
}
};
},
[classList, hostRef, ref, style]
);
}

View File

@@ -12,7 +12,6 @@
import dangerousStyleValue from '../dangerousStyleValue';
import hyphenateStyleName from 'hyphenate-style-name';
import warnValidStyle from '../warnValidStyle';
/**
* Sets the value for multiple styles on a node. If a value is specified as
@@ -21,18 +20,13 @@ import warnValidStyle from '../warnValidStyle';
* @param {DOMElement} node
* @param {object} styles
*/
function setValueForStyles(node, styles, getStack) {
function setValueForStyles(node, styles) {
const style = node.style;
for (let styleName in styles) {
if (!styles.hasOwnProperty(styleName)) {
continue;
}
const isCustomProperty = styleName.indexOf('--') === 0;
if (process.env.NODE_ENV !== 'production') {
if (!isCustomProperty) {
warnValidStyle(styleName, styles[styleName], getStack);
}
}
const styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty);
if (styleName === 'float') {
styleName = 'cssFloat';

View File

@@ -10,7 +10,7 @@ module.exports = {
// resetMocks: true,
rootDir: process.cwd(),
roots: ['<rootDir>/packages'],
setupFiles: ['jest-canvas-mock'],
setupFiles: ['jest-canvas-mock', require.resolve('./setupFiles.js')],
setupFilesAfterEnv: [require.resolve('./setupFramework.js')],
snapshotSerializers: ['enzyme-to-json/serializer'],
testEnvironment: 'jsdom',

View File

@@ -0,0 +1,10 @@
/* eslint-env jasmine, jest */
// JSDOM doesn't implement ResizeObserver
class ResizeObserver {
disconnect() {}
observe() {}
unobserve() {}
}
window.ResizeObserver = ResizeObserver;