diff --git a/packages/ui/Marquee/MarqueeController.js b/packages/ui/Marquee/MarqueeController.js index 44283b32ea..9d4ee4ae18 100644 --- a/packages/ui/Marquee/MarqueeController.js +++ b/packages/ui/Marquee/MarqueeController.js @@ -1,6 +1,7 @@ import {forward} from '@enact/core/handle'; import hoc from '@enact/core/hoc'; import {Job} from '@enact/core/util'; +import PropTypes from 'prop-types'; import React from 'react'; const STATE = { @@ -46,6 +47,20 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => { return class extends React.Component { static displayName = 'MarqueeController' + static propTypes = /** @lends ui/Marquee.MarqueeController.prototype */ { + /** + * Determines what triggers the marquee to start its animation. + * + * This property is passed down to any chirdren Marquee components, and is used there, + * unless `marqueeOn` is specified for them as well. + * + * @type {('focus'|'hover'|'render')} + * @default 'focus' + * @public + */ + marqueeOn: PropTypes.oneOf(['focus', 'hover', 'render']) + } + constructor (props) { super(props); @@ -56,6 +71,7 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => { complete: this.handleComplete, enter: this.handleEnter, leave: this.handleLeave, + marqueeOn: props.marqueeOn, register: this.handleRegister, start: this.handleStart, unregister: this.handleUnregister @@ -284,7 +300,7 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => { } render () { - let props = this.props; + let {...props} = this.props; if (marqueeOnFocus) { props = { @@ -294,6 +310,8 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => { }; } + delete props.marqueeOn; + return ( diff --git a/packages/ui/Marquee/MarqueeDecorator.js b/packages/ui/Marquee/MarqueeDecorator.js index 590f3196a0..f20187e086 100644 --- a/packages/ui/Marquee/MarqueeDecorator.js +++ b/packages/ui/Marquee/MarqueeDecorator.js @@ -114,6 +114,10 @@ const didPropChange = (propList, prev, next) => { return hasPropsChanged.indexOf(true) !== -1; }; +const getMarqueeOn = function (props, context, marqueeOnDefault = 'focus') { + return (props.marqueeOn || (context && context.marqueeOn) || marqueeOnDefault); +}; + /* * There's only one timer shared for Marquee so we need to keep track of what we may be using it * for. We may need to clean up certain things as we move among states. @@ -304,7 +308,6 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { static defaultProps = { marqueeDelay: 1000, - marqueeOn: 'focus', marqueeOnRenderDelay: 1000, marqueeResetDelay: 1000, marqueeSpacing: '50%', @@ -338,7 +341,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { } this.validateTextDirection(); - if (this.props.marqueeOn === 'render') { + if (getMarqueeOn(this.props, this.context) === 'render') { this.startAnimation(this.props.marqueeOnRenderDelay); } on('keydown', this.handlePointerHide); @@ -352,7 +355,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { } componentDidUpdate (prevProps) { - const {children, disabled, forceDirection, locale, marqueeOn, marqueeDisabled, marqueeSpacing, marqueeSpeed, rtl} = this.props; + const {children, disabled, forceDirection, locale, marqueeOn = getMarqueeOn(this.props, this.context), marqueeDisabled, marqueeSpacing, marqueeSpeed, rtl} = this.props; let forceRestartMarquee = false; @@ -371,7 +374,8 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { this.invalidateMetrics(); this.cancelAnimation(); } else if ( - prevProps.marqueeOn !== marqueeOn || + // prevProps.marqueeOn !== marqueeOn || + getMarqueeOn(prevProps, this.context) !== marqueeOn || prevProps.marqueeDisabled !== marqueeDisabled || prevProps.marqueeSpeed !== marqueeSpeed || prevProps.forceDirection !== forceDirection @@ -383,7 +387,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { this.validateTextDirection(); if (forceRestartMarquee || this.shouldStartMarquee()) { - this.tryStartingAnimation(this.props.marqueeOn === 'render' ? this.props.marqueeOnRenderDelay : this.props.marqueeDelay); + this.tryStartingAnimation(marqueeOn === 'render' ? this.props.marqueeOnRenderDelay : this.props.marqueeDelay); } } @@ -462,7 +466,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { * @returns {Boolean} - `true` if a possible marquee condition exists */ shouldStartMarquee () { - const {disabled, marqueeDisabled, marqueeOn} = this.props; + const {disabled, marqueeDisabled, marqueeOn = getMarqueeOn(this.props, this.context)} = this.props; return !marqueeDisabled && ( marqueeOn === 'render' || !this.sync && ( @@ -769,7 +773,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { forwardBlur(ev, this.props); if (this.isFocused) { this.isFocused = false; - if (!this.sync && !(this.isHovered && this.props.marqueeOn === 'hover')) { + if (!this.sync && !(this.isHovered && getMarqueeOn(this.props, this.context) === 'hover')) { this.cancelAnimation(); } } @@ -777,7 +781,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { handleEnter = (ev) => { this.isHovered = true; - if (this.props.marqueeOn === 'hover') { + if (getMarqueeOn(this.props, this.context) === 'hover') { if (this.sync) { this.context.enter(this); } else if (!this.state.animating) { @@ -801,7 +805,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { handleUnhover () { this.isHovered = false; - if (this.props.marqueeOn === 'hover') { + if (getMarqueeOn(this.props, this.context) === 'hover') { if (this.sync) { this.context.leave(this); } else { @@ -826,7 +830,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => { alignment, children, disabled, - marqueeOn, + marqueeOn = getMarqueeOn(this.props, this.context), marqueeSpeed, ...rest } = this.props;