Skip to content

Commit

Permalink
Merge pull request #9 from yaycmyk/react-compatibility
Browse files Browse the repository at this point in the history
Update React compatibility, bump to 1.1.0
  • Loading branch information
Evan Jacobs committed Jun 9, 2015
2 parents 0440f10 + 7db07cb commit 1e1e268
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 230 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## 1.1.0
### Bugfixes
- [Make module compatible with newer versions of React](https://github.com/enigma-io/react-input-placeholder/pull/7)
- [Check for document before using it](https://github.com/enigma-io/react-input-placeholder/pull/6)

### Deprecations
- Support for React versions `< 0.13.0` will be removed in `2.0.0`

## 1.0.0
- Initial commit
3 changes: 1 addition & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = function (grunt) {
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> - v <%= pkg.version %> - <%= pkg.author %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> (<%= grunt.template.today("yyyy-mm-dd") %>) - <%= pkg.author %> */\n'
},
dist: {
files: {
Expand All @@ -20,7 +20,6 @@ module.exports = function (grunt) {
},
jshint: {
options: {
indent: 2,
camelcase: true,
nonew: true,
plusplus: true,
Expand Down
2 changes: 1 addition & 1 deletion LICENSE → LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2014 Enigma Technologies, Inc.
Copyright (c) 2015 Enigma Technologies, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
React Input and Textarea with Placeholder Shim
=======================

`PlaceholderShim` provides `Input` and `Textarea`, small wrappers around `React.DOM.input` and `React.DOM.textarea` respectively that shims in `placeholder` functionality for browsers that don't natively support it. Currently only tested with IE9.
`PlaceholderShim` provides `Input` and `Textarea`, small wrappers around `React.createElement('input')` and `React.createElement('textarea')` respectively that shims in `placeholder` functionality for browsers that don't natively support it. Currently only tested with IE9.

Demo: http://jsfiddle.net/gb4xq/12/
Demo: https://jsfiddle.net/yaycmyk/69z2wepo/10029/

## Getting Started

### Browserify

Install: `npm install react-input-placeholder`

Require:
```

```js
Input = require('react-input-placeholder')(React).Input;
Textarea = require('react-input-placeholder')(React).Textarea;
```

### No module

The compiled component sits in the `dist` folder.
The compiled bundle sits in the `dist/` folder.

```
```js
<script src='dist/react-input-placeholder.min.js'></script>
<script>
var Input = PlaceholderShim.Input;
Expand All @@ -31,11 +31,13 @@ The compiled component sits in the `dist` folder.

## Usage

You can use `Input` or `Textarea` exactly the same way you'd use `React.DOM.Input`. All attributes will be passed on, and all event callbacks will be called. However, please note that the placeholder shim only works on [controlled](http://facebook.github.io/react/docs/forms.html#controlled-components) inputs (i.e., you must provide a `value` or `valueLink` prop).
You can use `Input` or `Textarea` exactly the same way you'd use `React.createElement('input')` or `<input />` in JSX. All attributes will be passed on, and all event callbacks will be called. However, please note that the placeholder shim only works on [controlled](http://facebook.github.io/react/docs/forms.html#controlled-components) inputs (i.e., you must provide a `value` or `valueLink` prop).

When the placeholder text is visible, the `placeholder` CSS class will be added to the `input` element so you can style it, e.g.
```
input.placeholder, textarea.placeholder {

```css
input.placeholder,
textarea.placeholder {
color: gray;
font-style: italic;
}
Expand All @@ -45,21 +47,21 @@ input.placeholder, textarea.placeholder {

Placeholder doesn't show on IE9.

```
```html
<input placeholder="Enter text here..." value={this.state.value} onChange={this.handleChange} />
```

### After

Works on IE9!

```
```html
<Input placeholder="Enter text here..." value={this.state.value} onChange={this.handleChange} />
```

## Building yourself

```
```shell
npm install
grunt dist
```
Expand Down
249 changes: 145 additions & 104 deletions dist/react-input-placeholder.js
Original file line number Diff line number Diff line change
@@ -1,117 +1,157 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var isPlaceholderSupported = (typeof document !== 'undefined') && 'placeholder' in document.createElement('input');

/**
* Input is a wrapper around React.DOM.input with a `placeholder` shim for IE9.
* NOTE: only supports "controlled" inputs (http://facebook.github.io/react/docs/forms.html#controlled-components)
*/
var createShimmedElement = function(React, elementConstructor, name) {
return React.createClass({
displayName: name,

componentWillMount: function() {
this.needsPlaceholding = this.props.placeholder && !isPlaceholderSupported;
},
componentWillReceiveProps: function(props) {
this.needsPlaceholding = props.placeholder && !isPlaceholderSupported;
},

// this component supports valueLink or value/onChange.
// borrowed from LinkedValueMixin.js
getValue: function() {
if (this.props.valueLink) {
return this.props.valueLink.value;
}
return this.props.value;
},
getOnChange: function() {
if (this.props.valueLink) {
return this._handleLinkedValueChange;
}
return this.props.onChange;
},
_handleLinkedValueChange: function(e) {
this.props.valueLink.requestChange(e.target.value);
},

// keep track of focus
onFocus: function(e) {
this.hasFocus = true;
this.setSelectionIfNeeded(e.target);
if (this.props.onFocus) { return this.props.onFocus(e); }
},
onBlur: function(e) {
this.hasFocus = false;
if (this.props.onBlur) { return this.props.onBlur(e); }
},

setSelectionIfNeeded: function(node) {
// if placeholder is visible, ensure cursor is at start of input
if (this.needsPlaceholding && this.hasFocus && this.isPlaceholding &&
(node.selectionStart !== 0 || node.selectionEnd !== 0)) {
node.setSelectionRange(0, 0);
return true;
}
return false;
},

onChange: function(e) {
if (this.isPlaceholding) {
// remove placeholder when text is added
var value = e.target.value,
i = value.indexOf(this.props.placeholder);
if (i !== -1) {
e.target.value = value.slice(0, i);
}
}
var onChange = this.getOnChange();
if (onChange) { return onChange(e); }
},

onSelect: function(e) {
if (this.isPlaceholding) {
this.setSelectionIfNeeded(e.target);
return false;
} else if (this.props.onSelect) {
return this.props.onSelect(e);
}
},

componentDidUpdate: function() {
this.setSelectionIfNeeded(this.getDOMNode());
},

render: function() {
var element = this.transferPropsTo(elementConstructor());
if (this.needsPlaceholding) {
// override valueLink and event handlers
element.props.onFocus = this.onFocus;
element.props.onBlur = this.onBlur;
element.props.onChange = this.onChange;
element.props.onSelect = this.onSelect;
element.props.valueLink = undefined;

var value = this.getValue();
if (!value) {
this.isPlaceholding = true;
value = this.props.placeholder;
element.props.type = 'text';
element.props.className += ' placeholder';
} else {
this.isPlaceholding = false;
return React.createClass({
displayName: name,

componentWillMount: function() {
this.needsPlaceholding = this.props.placeholder && !isPlaceholderSupported;
},
componentWillReceiveProps: function(props) {
this.needsPlaceholding = props.placeholder && !isPlaceholderSupported;
},

// this component supports valueLink or value/onChange.
// borrowed from LinkedValueMixin.js
getValue: function() {
if (this.props.valueLink) {
return this.props.valueLink.value;
}

return this.props.value;
},

getOnChange: function() {
if (this.props.valueLink) {
return this._handleLinkedValueChange;
}

return this.props.onChange;
},

_handleLinkedValueChange: function(e) {
this.props.valueLink.requestChange(e.target.value);
},

// keep track of focus
onFocus: function(e) {
this.hasFocus = true;
this.setSelectionIfNeeded(e.target);

if (this.props.onFocus) {
return this.props.onFocus(e);
}
},
onBlur: function(e) {
this.hasFocus = false;

if (this.props.onBlur) {
return this.props.onBlur(e);
}
},

setSelectionIfNeeded: function(node) {
// if placeholder is visible, ensure cursor is at start of input
if (this.needsPlaceholding &&
this.hasFocus &&
this.isPlaceholding &&
(node.selectionStart !== 0 || node.selectionEnd !== 0)) {
node.setSelectionRange(0, 0);

return true;
}

return false;
},

onChange: function(e) {
var onChange = this.getOnChange();
var value;
var index;

if (this.isPlaceholding) {
// remove placeholder when text is added
value = e.target.value;
index = value.indexOf(this.props.placeholder);

if (index !== -1) {
e.target.value = value.slice(0, index);
}
}

if (onChange) {
return onChange(e);
}
},

onSelect: function(e) {
if (this.isPlaceholding) {
this.setSelectionIfNeeded(e.target);

return false;
} else if (this.props.onSelect) {
return this.props.onSelect(e);
}
},

componentDidUpdate: function() {
this.setSelectionIfNeeded(this.getDOMNode());
},

render: function() {
var element;
var value;

if (!('createElement' in React)) { /* start -- to be removed in 2.0.0 */
element = this.transferPropsTo(elementConstructor());
} else { /* -- end */
element = React.createElement(elementConstructor, this.props, this.props.children);
}

if (this.needsPlaceholding) {
// override valueLink and event handlers
element.props.onFocus = this.onFocus;
element.props.onBlur = this.onBlur;
element.props.onChange = this.onChange;
element.props.onSelect = this.onSelect;
element.props.valueLink = undefined;

value = this.getValue();

if (!value) {
this.isPlaceholding = true;
value = this.props.placeholder;
element.props.type = 'text';
element.props.className += ' placeholder';
} else {
this.isPlaceholding = false;
}

element.props.value = value;
}

return element;
}
element.props.value = value;
}
return element;
}
});
});
};

module.exports = function(React) {
return {
Input: createShimmedElement(React, React.DOM.input, 'Input'),
Textarea: createShimmedElement(React, React.DOM.textarea, 'Textarea')
};
if (!('createElement' in React)) { /* start -- to be removed in 2.0.0 */
return {
Input: createShimmedElement(React, React.DOM.input, 'Input'),
Textarea: createShimmedElement(React, React.DOM.textarea, 'Textarea')
};
} else { /* -- end */
return {
Input: React.createFactory(createShimmedElement(React, 'input', 'Input')),
Textarea: React.createFactory(createShimmedElement(React, 'textarea', 'Textarea'))
};
}
};

},{}],2:[function(require,module,exports){
Expand All @@ -124,4 +164,5 @@ if (typeof define === 'function' && define.amd) {
} else {
window.PlaceholderShim = reactInputPlaceholder(window.React);
}
},{"./react-input-placeholder":1}]},{},[2])
},{"./react-input-placeholder":1}]},{},[2])
;
4 changes: 2 additions & 2 deletions dist/react-input-placeholder.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1e1e268

Please sign in to comment.