react-tour-guide
Advanced tools
| .tour-indicator { | ||
| height: 30px; | ||
| width: 30px; | ||
| -webkit-border-radius: 100%; | ||
| -moz-border-radius: 100%; | ||
| border-radius: 100%; | ||
| background-color: #3f94d0; | ||
| cursor: pointer; | ||
| /* Animate */ | ||
| -webkit-animation-name: pulse; | ||
| -webkit-animation-duration: 1.5s; | ||
| -webkit-animation-iteration-count: infinite; | ||
| -webkit-animation-timing-function: ease-out; | ||
| -moz-animation-name: pulse; | ||
| -moz-animation-duration: 1.5s; | ||
| -moz-animation-iteration-count: infinite; | ||
| -moz-animation-timing-function: ease-out; | ||
| -o-animation-name: pulse; | ||
| -o-animation-duration: 1.5s; | ||
| -o-animation-iteration-count: infinite; | ||
| -o-animation-timing-function: ease-out; | ||
| animation-name: pulse; | ||
| animation-duration: 1.5s; | ||
| animation-iteration-count: infinite; | ||
| animation-timing-function: ease-out; | ||
| } | ||
| /* WebKit/Safari and Chrome */ | ||
| @-webkit-keyframes pulse { | ||
| 0% { | ||
| -webkit-transform: scale(1); | ||
| transform: scale(1); | ||
| } | ||
| 80% { | ||
| -webkit-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| } | ||
| 100% { | ||
| -webkit-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Gecko/Firefox */ | ||
| @-moz-keyframes pulse { | ||
| 0% { | ||
| -moz-transform: scale(0.3); | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| -moz-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| -moz-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Presto/Opera */ | ||
| @-o-keyframes pulse { | ||
| 0% { | ||
| -o-transform: scale(0.3); | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| -o-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| -o-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Standard */ | ||
| @keyframes pulse { | ||
| 0% { | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| .tour-backdrop { | ||
| z-index: 998; /* one below z-index of tour-toolip (999) */ | ||
| position: fixed; | ||
| top: 0; | ||
| right: 0; | ||
| bottom: 0; | ||
| left: 0; | ||
| text-align: center; | ||
| background: rgba(0, 0, 0, 0.45); | ||
| } | ||
| .tour-tooltip { | ||
| width: 200px; | ||
| background-color: #ffffff; | ||
| color: #545454; | ||
| border: 1px solid #dddddd; | ||
| -webkit-border-radius: 4px; | ||
| -moz-border-radius: 4px; | ||
| border-radius: 4px; | ||
| padding: 5px; | ||
| -webkit-box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| -moz-box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| } | ||
| .tour-tooltip p { | ||
| margin: 5px 3px; | ||
| } | ||
| .tour-tooltip .tour-btn.close { | ||
| cursor: pointer; | ||
| display: block; | ||
| width: auto; | ||
| margin: 0 auto; | ||
| background-color: #ffffff; | ||
| border: 1px solid #dddddd; | ||
| -webkit-border-radius: 4px; | ||
| -moz-border-radius: 4px; | ||
| border-radius: 4px; | ||
| padding: 3px; | ||
| text-align: center; | ||
| } | ||
| .tour-tooltip .tour-btn.close:hover { | ||
| border-color: #3f94d0; | ||
| color: #3f94d0; | ||
| } |
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var Indicator = React.createClass({displayName: "Indicator", | ||
| propTypes: { | ||
| cssPosition: React.PropTypes.string.isRequired, | ||
| size: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| xPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| yPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| handleIndicatorClick: React.PropTypes.func.isRequired | ||
| }, | ||
| getDefaultProps: function() { | ||
| return { | ||
| cssPosition: 'absolute', | ||
| size: '30px', | ||
| xPos: 0, | ||
| yPos: 0 | ||
| }; | ||
| }, | ||
| render: function() { | ||
| var styles = { | ||
| 'position': this.props.cssPosition === 'fixed' ? 'fixed' : 'absolute', | ||
| 'top': this.props.yPos, | ||
| 'left': this.props.xPos, | ||
| 'width': this.props.size, | ||
| 'height': this.props.size | ||
| }; | ||
| return ( | ||
| React.createElement("div", {className: "tour-indicator", style: styles, onClick: this.props.handleIndicatorClick}) | ||
| ); | ||
| } | ||
| }); | ||
| module.exports = React.createFactory(Indicator); |
+204
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var $ = require('jquery'); | ||
| var Indicator = require('./Indicator'); | ||
| var Tooltip = require('./Tooltip'); | ||
| module.exports = function(settings, done) { | ||
| var mixin = { | ||
| settings: $.extend({ | ||
| scrollToSteps: true, | ||
| indicatorSize: 30, | ||
| tooltipWidth: 250, | ||
| steps: [] | ||
| }, settings), | ||
| completionCallback: done || function() {}, | ||
| getInitialState: function() { | ||
| return { | ||
| currentIndex: 0, | ||
| showTooltip: false | ||
| }; | ||
| }, | ||
| _renderLayer: function() { | ||
| // By calling this method in componentDidMount() and componentDidUpdate(), you're effectively | ||
| // creating a "wormhole" that funnels React's hierarchical updates through to a DOM node on an | ||
| // entirely different part of the page. | ||
| React.render(this.renderCurrentStep(), this._target); | ||
| }, | ||
| _unrenderLayer: function() { | ||
| React.unmountComponentAtNode(this._target); | ||
| }, | ||
| componentDidUpdate: function() { | ||
| if ( this.settings.steps[this.state.currentIndex] ) { | ||
| this._renderLayer(); | ||
| } else { | ||
| this.completionCallback(); | ||
| this._unrenderLayer(); | ||
| } | ||
| }, | ||
| componentDidMount: function() { | ||
| // Appending to the body is easier than managing the z-index of everything on the page. | ||
| // It's also better for accessibility and makes stacking a snap (since components will stack | ||
| // in mount order). | ||
| if ( this.settings.steps[this.state.currentIndex] ) { | ||
| this._target = document.createElement('div'); | ||
| document.body.appendChild(this._target); | ||
| this._renderLayer(); | ||
| } | ||
| }, | ||
| componentWillUnmount: function() { | ||
| this._unrenderLayer(); | ||
| document.body.removeChild(this._target); | ||
| }, | ||
| preventWindowOverflow: function(type, value, axis) { | ||
| var winWidth = parseInt($(window).width()); | ||
| var docHeight = parseInt($(document).height()); | ||
| var sizeVariable = type.toLowerCase() === 'indicator' ? this.settings.indicatorSize : this.settings.tooltipWidth; | ||
| if ( axis.toLowerCase() === 'x' ) { | ||
| if ( value + sizeVariable > winWidth ) { | ||
| value = winWidth - sizeVariable; | ||
| } else if ( value - sizeVariable/2 < 0 ) { | ||
| value = 0; | ||
| } | ||
| } else if ( axis.toLowerCase() === 'y' ) { | ||
| if ( value + sizeVariable/2 > docHeight ) { | ||
| value = docHeight - sizeVariable; | ||
| } else if ( value - sizeVariable/2 < 0 ) { | ||
| value = 0; | ||
| } | ||
| } | ||
| return value; | ||
| }, | ||
| calculatePlacement: function(step, $element) { | ||
| var offset = $element.offset(); | ||
| var width = $element.width(); | ||
| var height = $element.height(); | ||
| var position = step.position.toLowerCase(); | ||
| var topRegex = new RegExp('top', 'gi'); | ||
| var bottomRegex = new RegExp('bottom', 'gi'); | ||
| var leftRegex = new RegExp('left', 'gi'); | ||
| var rightRegex = new RegExp('right', 'gi'); | ||
| var placement = { | ||
| indicator: { | ||
| x: 0, | ||
| y: 0 | ||
| }, | ||
| tooltip: { | ||
| x: 0, | ||
| y: 0 | ||
| } | ||
| }; | ||
| // Calculate x positions | ||
| if ( leftRegex.test(position) ) { | ||
| placement.indicator.x = offset.left - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top - this.settings.tooltipWidth/4; | ||
| } else if ( rightRegex.test(position) ) { | ||
| placement.indicator.x = offset.left + width - this.settings.indicatorSize/2; | ||
| placement.tooltip.x = offset.left + width - this.settings.tooltipWidth/2; | ||
| } else { | ||
| placement.indicator.x = offset.left + width/2 - this.settings.indicatorSize/2; | ||
| placement.tooltip.x = offset.left + width/2 - this.settings.tooltipWidth/2; | ||
| } | ||
| // Calculate y positions | ||
| if ( topRegex.test(position) ) { | ||
| placement.indicator.y = offset.top - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top - this.settings.tooltipWidth/4; | ||
| } else if ( bottomRegex.test(position) ) { | ||
| placement.indicator.y = offset.top + height - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top + height - this.settings.tooltipWidth/4; | ||
| } else { | ||
| placement.indicator.y = offset.top + height/2 - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top + height/2 - this.settings.tooltipWidth/4; | ||
| } | ||
| return { | ||
| indicator: { | ||
| x: this.preventWindowOverflow('indicator', placement.indicator.x, 'x'), | ||
| y: this.preventWindowOverflow('indicator', placement.indicator.y, 'y') | ||
| }, | ||
| tooltip: { | ||
| x: this.preventWindowOverflow('tooltip', placement.tooltip.x, 'x'), | ||
| y: this.preventWindowOverflow('tooltip', placement.tooltip.y, 'y') | ||
| } | ||
| }; | ||
| }, | ||
| handleIndicatorClick: function(evt) { | ||
| evt.preventDefault(); | ||
| this.setState({ showTooltip: true }); | ||
| }, | ||
| closeTooltip: function(evt) { | ||
| evt.preventDefault(); | ||
| this.setState({ | ||
| showTooltip: false, | ||
| currentIndex: this.state.currentIndex + 1 | ||
| }, this.scrollToNextStep); | ||
| }, | ||
| scrollToNextStep: function() { | ||
| var $nextIndicator = $('.tour-indicator'); | ||
| if ( $nextIndicator && $nextIndicator.length && this.settings.scrollToSteps ) { | ||
| $('html, body').animate({ | ||
| 'scrollTop': $nextIndicator.offset().top - $(window).height()/2 | ||
| }, 500); | ||
| } | ||
| }, | ||
| renderCurrentStep: function() { | ||
| var element = null; | ||
| var currentStep = this.settings.steps[this.state.currentIndex]; | ||
| var $target = $(currentStep.element); | ||
| var cssPosition = $target.css('position'); | ||
| var placement = this.calculatePlacement(currentStep, $target); | ||
| if ( this.state.showTooltip ) { | ||
| element = ( | ||
| React.createElement(Tooltip, {cssPosition: cssPosition, | ||
| xPos: placement.tooltip.x, | ||
| yPos: placement.tooltip.y, | ||
| width: this.settings.tooltipWidth, | ||
| text: currentStep.text, | ||
| closeTooltip: this.closeTooltip}) | ||
| ); | ||
| } else { | ||
| element = ( | ||
| React.createElement(Indicator, {cssPosition: cssPosition, | ||
| xPos: placement.indicator.x, | ||
| yPos: placement.indicator.y, | ||
| size: this.settings.indicatorSize, | ||
| handleIndicatorClick: this.handleIndicatorClick}) | ||
| ); | ||
| } | ||
| return element; | ||
| } | ||
| }; | ||
| return mixin; | ||
| }; |
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var Tooltip = React.createClass({displayName: "Tooltip", | ||
| propTypes: { | ||
| cssPosition: React.PropTypes.string.isRequired, | ||
| xPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| yPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| width: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| text: React.PropTypes.string.isRequired, | ||
| closeTooltip: React.PropTypes.func.isRequired | ||
| }, | ||
| getDefaultProps: function() { | ||
| return { | ||
| cssPosition: 'absolute', | ||
| xPos: 0, | ||
| yPos: 0, | ||
| text: '' | ||
| }; | ||
| }, | ||
| render: function() { | ||
| var styles = { | ||
| 'position': this.props.cssPosition === 'fixed' ? 'fixed' : 'absolute', | ||
| 'top': this.props.yPos, | ||
| 'left': this.props.xPos, | ||
| 'width': this.props.width | ||
| }; | ||
| return ( | ||
| React.createElement("div", null, | ||
| React.createElement("div", {className: "tour-backdrop", onClick: this.props.closeTooltip}), | ||
| React.createElement("div", {className: "tour-tooltip", style: styles}, | ||
| React.createElement("p", null, this.props.text), | ||
| React.createElement("div", {className: "tour-btn close", onClick: this.props.closeTooltip}, "Close") | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| }); | ||
| module.exports = React.createFactory(Tooltip); |
+3
-3
@@ -6,8 +6,8 @@ | ||
| Mixin: require('./lib/js/Mixin'), | ||
| Mixin: require('./dist/js/Mixin'), | ||
| Indicator: require('./lib/js/Indicator'), | ||
| Indicator: require('./dist/js/Indicator'), | ||
| Tooltip: require('./lib/js/Tooltip') | ||
| Tooltip: require('./dist/js/Tooltip') | ||
| }; |
+7
-1
| { | ||
| "name": "react-tour-guide", | ||
| "version": "0.0.2", | ||
| "version": "0.0.3", | ||
| "author": "Jake Marsh <jakemmarsh@gmail.com>", | ||
@@ -24,3 +24,9 @@ "description": "A ReactJS mixin to give new users a popup-based tour of your application.", | ||
| "jquery": "^2.1.3" | ||
| }, | ||
| "devDependencies": { | ||
| "del": "^1.1.1", | ||
| "gulp": "^3.8.11", | ||
| "gulp-react": "^3.0.0", | ||
| "run-sequence": "^1.0.2" | ||
| } | ||
| } |
+2
-1
@@ -90,3 +90,4 @@ react-tour-guide [](http://badge.fury.io/js/react-tour-guide) | ||
| ```html | ||
| <div class="tour-backdrop"> | ||
| <div> | ||
| <div class="tour-backdrop"></div> | ||
| <div class="tour-tooltip"> | ||
@@ -93,0 +94,0 @@ <p>{The step's text goes here.}</p> |
-19
| { | ||
| "node": true, | ||
| "browser": true, | ||
| "esnext": true, | ||
| "bitwise": true, | ||
| "curly": true, | ||
| "eqeqeq": true, | ||
| "immed": true, | ||
| "indent": 2, | ||
| "latedef": true, | ||
| "noarg": true, | ||
| "regexp": true, | ||
| "undef": true, | ||
| "unused": true, | ||
| "strict": true, | ||
| "trailing": true, | ||
| "smarttabs": true, | ||
| "newcap": false | ||
| } |
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var Indicator = React.createClass({ | ||
| propTypes: { | ||
| cssPosition: React.PropTypes.string.isRequired, | ||
| size: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| xPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| yPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| handleIndicatorClick: React.PropTypes.func.isRequired | ||
| }, | ||
| getDefaultProps: function() { | ||
| return { | ||
| cssPosition: 'absolute', | ||
| size: '30px', | ||
| xPos: 0, | ||
| yPos: 0 | ||
| }; | ||
| }, | ||
| render: function() { | ||
| var styles = { | ||
| 'position': this.props.cssPosition === 'fixed' ? 'fixed' : 'absolute', | ||
| 'top': this.props.yPos, | ||
| 'left': this.props.xPos, | ||
| 'width': this.props.size, | ||
| 'height': this.props.size | ||
| }; | ||
| return ( | ||
| <div className="tour-indicator" style={styles} onClick={this.props.handleIndicatorClick} /> | ||
| ); | ||
| } | ||
| }); | ||
| module.exports = React.createFactory(Indicator); |
-206
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var $ = require('jquery'); | ||
| var Indicator = require('./Indicator'); | ||
| var Tooltip = require('./Tooltip'); | ||
| window.jQuery = $; | ||
| module.exports = function(settings, done) { | ||
| var mixin = { | ||
| settings: $.extend({ | ||
| scrollToSteps: true, | ||
| indicatorSize: 30, | ||
| tooltipWidth: 250, | ||
| steps: [] | ||
| }, settings), | ||
| completionCallback: done || function() {}, | ||
| getInitialState: function() { | ||
| return { | ||
| currentIndex: 0, | ||
| showTooltip: false | ||
| }; | ||
| }, | ||
| _renderLayer: function() { | ||
| // By calling this method in componentDidMount() and componentDidUpdate(), you're effectively | ||
| // creating a "wormhole" that funnels React's hierarchical updates through to a DOM node on an | ||
| // entirely different part of the page. | ||
| React.render(this.renderCurrentStep(), this._target); | ||
| }, | ||
| _unrenderLayer: function() { | ||
| React.unmountComponentAtNode(this._target); | ||
| }, | ||
| componentDidUpdate: function() { | ||
| if ( this.settings.steps[this.state.currentIndex] ) { | ||
| this._renderLayer(); | ||
| } else { | ||
| this.completionCallback(); | ||
| this._unrenderLayer(); | ||
| } | ||
| }, | ||
| componentDidMount: function() { | ||
| // Appending to the body is easier than managing the z-index of everything on the page. | ||
| // It's also better for accessibility and makes stacking a snap (since components will stack | ||
| // in mount order). | ||
| if ( this.settings.steps[this.state.currentIndex] ) { | ||
| this._target = document.createElement('div'); | ||
| document.body.appendChild(this._target); | ||
| this._renderLayer(); | ||
| } | ||
| }, | ||
| componentWillUnmount: function() { | ||
| this._unrenderLayer(); | ||
| document.body.removeChild(this._target); | ||
| }, | ||
| preventWindowOverflow: function(type, value, axis) { | ||
| var winWidth = parseInt($(window).width()); | ||
| var docHeight = parseInt($(document).height()); | ||
| var sizeVariable = type.toLowerCase() === 'indicator' ? this.settings.indicatorSize : this.settings.tooltipWidth; | ||
| if ( axis.toLowerCase() === 'x' ) { | ||
| if ( value + sizeVariable > winWidth ) { | ||
| value = winWidth - sizeVariable; | ||
| } else if ( value - sizeVariable/2 < 0 ) { | ||
| value = 0; | ||
| } | ||
| } else if ( axis.toLowerCase() === 'y' ) { | ||
| if ( value + sizeVariable/2 > docHeight ) { | ||
| value = docHeight - sizeVariable; | ||
| } else if ( value - sizeVariable/2 < 0 ) { | ||
| value = 0; | ||
| } | ||
| } | ||
| return value; | ||
| }, | ||
| calculatePlacement: function(step, $element) { | ||
| var offset = $element.offset(); | ||
| var width = $element.width(); | ||
| var height = $element.height(); | ||
| var position = step.position.toLowerCase(); | ||
| var topRegex = new RegExp('top', 'gi'); | ||
| var bottomRegex = new RegExp('bottom', 'gi'); | ||
| var leftRegex = new RegExp('left', 'gi'); | ||
| var rightRegex = new RegExp('right', 'gi'); | ||
| var placement = { | ||
| indicator: { | ||
| x: 0, | ||
| y: 0 | ||
| }, | ||
| tooltip: { | ||
| x: 0, | ||
| y: 0 | ||
| } | ||
| }; | ||
| // Calculate x positions | ||
| if ( leftRegex.test(position) ) { | ||
| placement.indicator.x = offset.left - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top - this.settings.tooltipWidth/4; | ||
| } else if ( rightRegex.test(position) ) { | ||
| placement.indicator.x = offset.left + width - this.settings.indicatorSize/2; | ||
| placement.tooltip.x = offset.left + width - this.settings.tooltipWidth/2; | ||
| } else { | ||
| placement.indicator.x = offset.left + width/2 - this.settings.indicatorSize/2; | ||
| placement.tooltip.x = offset.left + width/2 - this.settings.tooltipWidth/2; | ||
| } | ||
| // Calculate y positions | ||
| if ( topRegex.test(position) ) { | ||
| placement.indicator.y = offset.top - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top - this.settings.tooltipWidth/4; | ||
| } else if ( bottomRegex.test(position) ) { | ||
| placement.indicator.y = offset.top + height - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top + height - this.settings.tooltipWidth/4; | ||
| } else { | ||
| placement.indicator.y = offset.top + height/2 - this.settings.indicatorSize/2; | ||
| placement.tooltip.y = offset.top + height/2 - this.settings.tooltipWidth/4; | ||
| } | ||
| return { | ||
| indicator: { | ||
| x: this.preventWindowOverflow('indicator', placement.indicator.x, 'x'), | ||
| y: this.preventWindowOverflow('indicator', placement.indicator.y, 'y') | ||
| }, | ||
| tooltip: { | ||
| x: this.preventWindowOverflow('tooltip', placement.tooltip.x, 'x'), | ||
| y: this.preventWindowOverflow('tooltip', placement.tooltip.y, 'y') | ||
| } | ||
| }; | ||
| }, | ||
| handleIndicatorClick: function(evt) { | ||
| evt.preventDefault(); | ||
| this.setState({ showTooltip: true }); | ||
| }, | ||
| closeTooltip: function(evt) { | ||
| evt.preventDefault(); | ||
| this.setState({ | ||
| showTooltip: false, | ||
| currentIndex: this.state.currentIndex + 1 | ||
| }, this.scrollToNextStep); | ||
| }, | ||
| scrollToNextStep: function() { | ||
| var $nextIndicator = $('.tour-indicator'); | ||
| if ( $nextIndicator && $nextIndicator.length && this.settings.scrollToSteps ) { | ||
| $('html, body').animate({ | ||
| 'scrollTop': $nextIndicator.offset().top - $(window).height()/2 | ||
| }, 500); | ||
| } | ||
| }, | ||
| renderCurrentStep: function() { | ||
| var element = null; | ||
| var currentStep = this.settings.steps[this.state.currentIndex]; | ||
| var $target = $(currentStep.element); | ||
| var cssPosition = $target.css('position'); | ||
| var placement = this.calculatePlacement(currentStep, $target); | ||
| if ( this.state.showTooltip ) { | ||
| element = ( | ||
| <Tooltip cssPosition={cssPosition} | ||
| xPos={placement.tooltip.x} | ||
| yPos={placement.tooltip.y} | ||
| width={this.settings.tooltipWidth} | ||
| text={currentStep.text} | ||
| closeTooltip={this.closeTooltip} /> | ||
| ); | ||
| } else { | ||
| element = ( | ||
| <Indicator cssPosition={cssPosition} | ||
| xPos={placement.indicator.x} | ||
| yPos={placement.indicator.y} | ||
| size={this.settings.indicatorSize} | ||
| handleIndicatorClick={this.handleIndicatorClick} /> | ||
| ); | ||
| } | ||
| return element; | ||
| } | ||
| }; | ||
| return mixin; | ||
| }; |
| /** | ||
| * @jsx React.DOM | ||
| */ | ||
| 'use strict'; | ||
| var React = require('react/addons'); | ||
| var Tooltip = React.createClass({ | ||
| propTypes: { | ||
| cssPosition: React.PropTypes.string.isRequired, | ||
| xPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| yPos: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| width: React.PropTypes.oneOfType([ | ||
| React.PropTypes.number, | ||
| React.PropTypes.string | ||
| ]).isRequired, | ||
| text: React.PropTypes.string.isRequired, | ||
| closeTooltip: React.PropTypes.func.isRequired | ||
| }, | ||
| getDefaultProps: function() { | ||
| return { | ||
| cssPosition: 'absolute', | ||
| xPos: 0, | ||
| yPos: 0, | ||
| text: '' | ||
| }; | ||
| }, | ||
| render: function() { | ||
| var styles = { | ||
| 'position': this.props.cssPosition === 'fixed' ? 'fixed' : 'absolute', | ||
| 'top': this.props.yPos, | ||
| 'left': this.props.xPos, | ||
| 'width': this.props.width | ||
| }; | ||
| return ( | ||
| <div> | ||
| <div className="tour-backdrop" onClick={this.props.closeTooltip} /> | ||
| <div className="tour-tooltip" style={styles}> | ||
| <p>{this.props.text}</p> | ||
| <div className="tour-btn close" onClick={this.props.closeTooltip}>Close</div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| }); | ||
| module.exports = React.createFactory(Tooltip); |
| .tour-indicator { | ||
| height: 30px; | ||
| width: 30px; | ||
| -webkit-border-radius: 100%; | ||
| -moz-border-radius: 100%; | ||
| border-radius: 100%; | ||
| background-color: #3f94d0; | ||
| cursor: pointer; | ||
| /* Animate */ | ||
| -webkit-animation-name: pulse; | ||
| -webkit-animation-duration: 1.5s; | ||
| -webkit-animation-iteration-count: infinite; | ||
| -webkit-animation-timing-function: ease-out; | ||
| -moz-animation-name: pulse; | ||
| -moz-animation-duration: 1.5s; | ||
| -moz-animation-iteration-count: infinite; | ||
| -moz-animation-timing-function: ease-out; | ||
| -o-animation-name: pulse; | ||
| -o-animation-duration: 1.5s; | ||
| -o-animation-iteration-count: infinite; | ||
| -o-animation-timing-function: ease-out; | ||
| animation-name: pulse; | ||
| animation-duration: 1.5s; | ||
| animation-iteration-count: infinite; | ||
| animation-timing-function: ease-out; | ||
| } | ||
| /* WebKit/Safari and Chrome */ | ||
| @-webkit-keyframes pulse { | ||
| 0% { | ||
| -webkit-transform: scale(1); | ||
| transform: scale(1); | ||
| } | ||
| 80% { | ||
| -webkit-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| } | ||
| 100% { | ||
| -webkit-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Gecko/Firefox */ | ||
| @-moz-keyframes pulse { | ||
| 0% { | ||
| -moz-transform: scale(0.3); | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| -moz-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| -moz-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Presto/Opera */ | ||
| @-o-keyframes pulse { | ||
| 0% { | ||
| -o-transform: scale(0.3); | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| -o-transform: scale(1.5); | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| -o-transform: scale(2.5); | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| /* Standard */ | ||
| @keyframes pulse { | ||
| 0% { | ||
| transform: scale(0.3); | ||
| opacity: 0.5; | ||
| } | ||
| 80% { | ||
| transform: scale(1.5); | ||
| opacity: 0; | ||
| } | ||
| 100% { | ||
| transform: scale(2.5); | ||
| opacity: 0; | ||
| } | ||
| } | ||
| .tour-backdrop { | ||
| z-index: 998; /* one below z-index of tour-toolip (999) */ | ||
| position: fixed; | ||
| top: 0; | ||
| right: 0; | ||
| bottom: 0; | ||
| left: 0; | ||
| text-align: center; | ||
| background: rgba(0, 0, 0, 0.45); | ||
| } | ||
| .tour-tooltip { | ||
| width: 200px; | ||
| background-color: #ffffff; | ||
| color: #545454; | ||
| border: 1px solid #dddddd; | ||
| -webkit-border-radius: 4px; | ||
| -moz-border-radius: 4px; | ||
| border-radius: 4px; | ||
| padding: 5px; | ||
| -webkit-box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| -moz-box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| box-shadow: 0 8px 6px -6px rgba(0,0,0,0.4); | ||
| } | ||
| .tour-tooltip p { | ||
| margin: 5px 3px; | ||
| } | ||
| .tour-tooltip .tour-btn.close { | ||
| cursor: pointer; | ||
| display: block; | ||
| width: auto; | ||
| margin: 0 auto; | ||
| background-color: #ffffff; | ||
| border: 1px solid #dddddd; | ||
| -webkit-border-radius: 4px; | ||
| -moz-border-radius: 4px; | ||
| border-radius: 4px; | ||
| padding: 3px; | ||
| text-align: center; | ||
| } | ||
| .tour-tooltip .tour-btn.close:hover { | ||
| border-color: #3f94d0; | ||
| color: #3f94d0; | ||
| } |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
97
1.04%17155
-2.88%4
Infinity%9
-10%404
-0.25%