Skip to content

Commit 1e727fb

Browse files
committed
Unify prefix handling; note that user-select and transform may have different vendor prefixes
1 parent 9a2817b commit 1e727fb

File tree

3 files changed

+51
-32
lines changed

3 files changed

+51
-32
lines changed

lib/utils/domFns.es6

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @flow
22
import {findInArray, isFunction, isNum, int} from './shims';
3-
import browserPrefix from './getPrefix';
3+
import browserPrefix, {getPrefix, browserPrefixToStyle, browserPrefixToKey} from './getPrefix';
44
import ReactDOM from 'react-dom';
55

66
import type Draggable from '../Draggable';
@@ -103,12 +103,7 @@ export function innerWidth(node: HTMLElement): number {
103103

104104
export function createCSSTransform({x, y}: {x: number, y: number}): Object {
105105
// Replace unitless items with px
106-
let out = {transform: 'translate(' + x + 'px,' + y + 'px)'};
107-
// Add single prefixed property as well
108-
if (browserPrefix) {
109-
out[browserPrefix + 'Transform'] = out.transform;
110-
}
111-
return out;
106+
return {[browserPrefixToKey('transform', browserPrefix)]: 'translate(' + x + 'px,' + y + 'px)'};
112107
}
113108

114109
export function createSVGTransform({x, y}: {x: number, y: number}): string {
@@ -118,7 +113,9 @@ export function createSVGTransform({x, y}: {x: number, y: number}): string {
118113
// User-select Hacks:
119114
//
120115
// Useful for preventing blue highlights all over everything when dragging.
121-
const userSelectStyle = `;${browserPrefix ? `-${browserPrefix.toLowerCase()}-` : ''}user-select: none;`;
116+
const userSelectPrefix = getPrefix('user-select');
117+
const userSelect = browserPrefixToStyle('user-select', userSelectPrefix);
118+
const userSelectStyle = `;${userSelect}: none;`;
122119

123120
export function addUserSelectStyles() {
124121
let style = document.body.getAttribute('style') || '';

lib/utils/getPrefix.es6

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,47 @@
11
// @flow
2-
export function generatePrefix(): string {
2+
const prefixes = ['Moz', 'Webkit', 'O', 'ms'];
3+
export function getPrefix(prop: string='transform'): string {
34
// Checking specifically for 'window.document' is for pseudo-browser server-side
45
// environments that define 'window' as the global context.
56
// E.g. React-rails (see https://github.com/reactjs/react-rails/pull/84)
67
if (typeof window === 'undefined' || typeof window.document === 'undefined') return '';
78

8-
const prefixes = ['Moz', 'Webkit', 'O', 'ms'];
99
const style = window.document.documentElement.style;
1010

11-
if ('transform' in style) {
12-
return '';
11+
if (prop in style) return '';
12+
13+
for (let i = 0; i < prefixes.length; i++) {
14+
if (browserPrefixToStyle(prop, prefixes[i]) in style) return prefixes[i];
1315
}
1416

15-
for (let i = 0; i < prefixes.length; ++i) {
16-
if (prefixes[i] + 'Transform' in style) {
17-
return prefixes[i];
17+
return '';
18+
}
19+
20+
export function browserPrefixToKey(prop: string, prefix: string): string {
21+
return prefix ? `${prefix}${kebabToTitleCase(prop)}` : prop;
22+
}
23+
24+
export function browserPrefixToStyle(prop: string, prefix: string): string {
25+
return prefix ? `-${prefix.toLowerCase()}-${prop}` : prop;
26+
}
27+
28+
function kebabToTitleCase(str: string): string {
29+
let out = '';
30+
let shouldCapitalize = true;
31+
for (let i = 0; i < str.length; i++) {
32+
if (shouldCapitalize) {
33+
out += str[i].toUpperCase();
34+
shouldCapitalize = false;
35+
} else if (str[i] === '-') {
36+
shouldCapitalize = true;
37+
} else {
38+
out += str[i];
1839
}
1940
}
20-
return '';
41+
return out;
2142
}
2243

23-
export default generatePrefix();
44+
// Default export is the prefix itself, like 'Moz', 'Webkit', etc
45+
// Note that you may have to re-test for certain things; for instance, Chrome 50
46+
// can handle unprefixed `transform`, but not unprefixed `user-select`
47+
export default getPrefix();

specs/draggable.spec.jsx

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/*eslint no-unused-vars:0*/
2-
var React = require('react');
3-
var ReactDOM = require('react-dom');
4-
var TestUtils = require('react/lib/ReactTestUtils');
5-
var Draggable = require('../index');
6-
var DraggableCore = require('../index').DraggableCore;
7-
var _ = require('lodash');
8-
var browserPrefix = require('../lib/utils/getPrefix.es6').default;
9-
var dashedBrowserPrefix = browserPrefix ? '-' + browserPrefix.toLowerCase() + '-' : '';
2+
import React from 'react';
3+
import ReactDOM from 'react-dom';
4+
import TestUtils from 'react/lib/ReactTestUtils';
5+
import Draggable, {DraggableCore} from '../index';
6+
import _ from 'lodash';
7+
import {getPrefix, browserPrefixToKey, browserPrefixToStyle} from '../lib/utils/getPrefix';
8+
const transformStyle = browserPrefixToStyle('transform', getPrefix('transform'));
9+
const transformKey = browserPrefixToKey('transform', getPrefix('transform'));
10+
const userSelectStyle = browserPrefixToStyle('user-select', getPrefix('user-select'));
1011

1112
/*global describe,it,expect,afterEach */
1213
describe('react-draggable', function () {
@@ -45,7 +46,7 @@ describe('react-draggable', function () {
4546
expect(node.getAttribute('style')).toMatch('touch-action: none');
4647
}
4748
expect(node.getAttribute('style')).toMatch('color: black');
48-
expect(node.getAttribute('style')).toMatch(dashedBrowserPrefix + 'transform: translate\\\(0px, 0px\\\)');
49+
expect(node.getAttribute('style')).toMatch(transformStyle + ': translate\\\(0px, 0px\\\)');
4950
expect(node.getAttribute('class')).toEqual('foo react-draggable');
5051
});
5152

@@ -61,7 +62,7 @@ describe('react-draggable', function () {
6162
<div
6263
className="react-draggable"
6364
style={{
64-
[browserPrefix + 'Transform']: 'translate(0px, 0px)'
65+
[transformKey]: 'translate(0px, 0px)'
6566
}}
6667
transform={null} />
6768
</DraggableCore>
@@ -267,8 +268,7 @@ describe('react-draggable', function () {
267268
});
268269

269270
it('should add and remove user-select styles', function () {
270-
// Karma runs in firefox in our tests
271-
var userSelectStyle = ';' + dashedBrowserPrefix + 'user-select: none;';
271+
var userSelectStyleStr = `;${userSelectStyle}: none;`;
272272

273273
drag = TestUtils.renderIntoDocument(
274274
<Draggable>
@@ -280,14 +280,12 @@ describe('react-draggable', function () {
280280

281281
expect(document.body.getAttribute('style')).toEqual('');
282282
TestUtils.Simulate.mouseDown(node, {clientX: 0, clientY: 0});
283-
expect(document.body.getAttribute('style')).toEqual(userSelectStyle);
283+
expect(document.body.getAttribute('style')).toEqual(userSelectStyleStr);
284284
TestUtils.Simulate.mouseUp(node);
285285
expect(document.body.getAttribute('style')).toEqual('');
286286
});
287287

288288
it('should not add and remove user-select styles when disabled', function () {
289-
// Karma runs in firefox in our tests
290-
var userSelectStyle = ';' + dashedBrowserPrefix + 'user-select: none;';
291289

292290
drag = TestUtils.renderIntoDocument(
293291
<Draggable enableUserSelectHack={false}>

0 commit comments

Comments
 (0)