diff --git a/examples/copy-button.jsx b/examples/copy-button.jsx new file mode 100644 index 0000000..dbc3f16 --- /dev/null +++ b/examples/copy-button.jsx @@ -0,0 +1,17 @@ +const CopyForm = React.createClass({ + _getTarget: function() { + return this.targetElement; + }, + render: function() { + return ( +
+ this.targetElement = ref} + /> + +
+ ); + }, +}); + +return ; diff --git a/js/copy-button.jsx b/js/copy-button.jsx new file mode 100644 index 0000000..fc8f3b4 --- /dev/null +++ b/js/copy-button.jsx @@ -0,0 +1,79 @@ +const React = require("react"); + +/* Copy to clipboard button + * attach to input, textarea or any other "text container" (div, span, label..) + */ +const CopyButton = React.createClass({ + propTypes: { + className: React.PropTypes.string, + defaultLabel: React.PropTypes.string, + didCopyLabel: React.PropTypes.string, + notSupportedLabel: React.PropTypes.string, + notSupportedLabelMac: React.PropTypes.string, + targetElement: React.PropTypes.func.isRequired, + }, + getDefaultProps: function() { + return { + defaultLabel: "Copy", + didCopyLabel: "Copied", + notSupportedLabel: "Ctrl+C to copy", + notSupportedLabelMac: "⌘-C to copy", + }; + }, + getInitialState: function() { + return {text: this.props.defaultLabel}; + }, + _copy: function() { + const element = this.props.targetElement(); + const selection = window.getSelection(); + + if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + element.focus(); + element.setSelectionRange(0, element.value.length); + } else { + const range = document.createRange(); + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); + } + + const result = document.execCommand('copy'); + this._handleResult(result, selection); + }, + _handleResult: function(result, selection) { + let label; + if (!result) { + if (navigator.platform.indexOf("Mac") !== -1) { + label = this.props.notSupportedLabelMac; + } else { + label = this.props.notSupportedLabel; + } + } else { + label = this.props.didCopyLabel; + this.props.targetElement().blur(); + selection.removeAllRanges(); + } + + this.setState({ + text: label, + }); + const _this = this; + setTimeout(function() { + _this.setState({ + text: _this.props.defaultLabel, + }); + }, 1000); + }, + render: function() { + return ( + + ); + }, +}); + +module.exports = CopyButton; diff --git a/reactify-components.jsx b/reactify-components.jsx index 9c92a0c..badaec8 100644 --- a/reactify-components.jsx +++ b/reactify-components.jsx @@ -25,6 +25,7 @@ window.TimeAgo = require("./js/timeago.jsx"); window.TimeoutTransitionGroup = require("./js/timeout-transition-group.jsx"); window.Tooltip = require("./js/tooltip.jsx"); window.WindowDrag = require("./js/window-drag.jsx"); +window.CopyButton = require("./js/copy-button.jsx"); // Create a for each example. var examples = document.querySelectorAll('div.example_div'); diff --git a/template.html b/template.html index a95e301..6cf3cb7 100644 --- a/template.html +++ b/template.html @@ -161,6 +161,7 @@

Components

  • Timeout Transition Group
  • Backbone Mixin
  • Window Drag
  • +
  • Copy to clipboard button
  • @@ -257,6 +258,12 @@

    Window Drag

    Detect drags into and out of the page.

    {% code_example "window-drag.jsx" %} +

    Copy to clipboard button

    + {{ stability("experimental") }} + {{ depends([]) }} +

    Copies input, textarea or other text content to clipboard.

    + {% code_example "copy-button.jsx" %} +

    Timeout Transition Group

    {{ stability("unstable") }} {{ depends([("http://jquery.com/", "jQuery")]) }}