[add] UIManager: 'blur', 'focus' and 'measureInWindow'

This commit is contained in:
Nicolas Gallagher
2016-03-15 13:14:06 -07:00
parent 8441755d61
commit 3e7cd1a001
3 changed files with 99 additions and 11 deletions

View File

@@ -0,0 +1,24 @@
// { scale: 2 } => 'scale(2)'
const mapTransform = (transform) => {
var key = Object.keys(transform)[0]
return `${key}(${transform[key]})`
}
// [1,2,3,4,5,6] => 'matrix3d(1,2,3,4,5,6)'
const convertTransformMatrix = (transformMatrix) => {
var matrix = transformMatrix.join(',')
return `matrix3d(${matrix})`
}
const processTransform = (style) => {
if (style) {
if (style.transform) {
style.transform = style.transform.map(mapTransform).join(' ')
} else if (style.transformMatrix) {
style.transformMatrix = convertTransformMatrix(style.transformMatrix)
}
}
return style
}
module.exports = processTransform

View File

@@ -73,8 +73,28 @@ suite('apis/UIManager', () => {
})
})
suite('measureInWindow', () => {
test('provides correct layout to callback', () => {
const node = createNode({ height: '10px', width: '10px' })
const middle = createNode({ padding: '20px' })
const context = createNode({ padding: '20px' })
middle.appendChild(node)
context.appendChild(middle)
document.body.appendChild(context)
UIManager.measureInWindow(node, (x, y, width, height) => {
assert.equal(x, 40)
assert.equal(y, 40)
assert.equal(width, 10)
assert.equal(height, 10)
})
document.body.removeChild(context)
})
})
suite('updateView', () => {
test('adds new className to existing className', () => {
test('add new className to existing className', () => {
const node = createNode()
node.className = 'existing'
const props = { className: 'extra' }
@@ -89,7 +109,20 @@ suite('apis/UIManager', () => {
assert.equal(node.getAttribute('style'), 'color: red; opacity: 0;')
})
test('sets attribute values', () => {
test('replaces input and textarea text', () => {
const node = createNode()
node.value = 'initial'
const textProp = { text: 'expected-text' }
const valueProp = { value: 'expected-value' }
UIManager.updateView(node, textProp)
assert.equal(node.value, 'expected-text')
UIManager.updateView(node, valueProp)
assert.equal(node.value, 'expected-value')
})
test('sets other attribute values', () => {
const node = createNode()
const props = { 'aria-level': '4', 'data-of-type': 'string' }
UIManager.updateView(node, props)

View File

@@ -1,6 +1,8 @@
import CSSPropertyOperations from 'react/lib/CSSPropertyOperations'
import flattenStyle from '../StyleSheet/flattenStyle'
import processTransform from '../StyleSheet/processTransform'
const measureAll = (node, callback, relativeToNativeNode) => {
const _measureLayout = (node, relativeToNativeNode, callback) => {
const relativeNode = relativeToNativeNode || node.parentNode
const relativeRect = relativeNode.getBoundingClientRect()
const { height, left, top, width } = node.getBoundingClientRect()
@@ -10,23 +12,52 @@ const measureAll = (node, callback, relativeToNativeNode) => {
}
const UIManager = {
blur(node) {
try { node.blur() } catch (err) {}
},
focus(node) {
try { node.focus() } catch (err) {}
},
measure(node, callback) {
measureAll(node, callback)
_measureLayout(node, null, callback)
},
measureInWindow(node, callback) {
const { height, left, top, width } = node.getBoundingClientRect()
callback(left, top, width, height)
},
measureLayout(node, relativeToNativeNode, onFail, onSuccess) {
measureAll(node, (x, y, width, height) => onSuccess(x, y, width, height), relativeToNativeNode)
const relativeTo = relativeToNativeNode || node.parentNode
_measureLayout(node, relativeTo, onSuccess)
},
updateView(node, props) {
for (const prop in props) {
let nativeProp
const value = props[prop]
if (prop === 'style') {
CSSPropertyOperations.setValueForStyles(node, value)
} else if (prop === 'className') {
node.classList.add(value)
} else {
node.setAttribute(prop, value)
switch(prop) {
case 'style':
// convert styles to DOM-styles
CSSPropertyOperations.setValueForStyles(node, processTransform(flattenStyle(value)))
break;
case 'class':
case 'className':
nativeProp = 'class'
// prevent class names managed by React Native from being replaced
const className = node.getAttribute(nativeProp) + ' ' + value
node.setAttribute(nativeProp, className)
break;
case 'text':
case 'value':
// native platforms use `text` prop to replace text input value
node.value = value
break;
default:
node.setAttribute(prop, value)
}
}
}