Skip to content

Commit 9f96386

Browse files
webOS101aarontam
authored andcommitted
Feature/enyo 4811 roysutton (#1301)
* Allow MarqueeController more control Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Apply same to focus/blur Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix Spottable and PickerButton Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Stop job on unmount Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Don't clobber handlers for joined picker Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Make sure joined is boolean Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix leaving picker button after disable Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Trigger with disabled joined button Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix LabeledItem to marquee on disabled * Allow disabled joined picker to marquee Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix linter warning Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Allow non-joined Picker to handle onMouseEnter/Leave * Fix test * Fixes up change log entry positioning * Fixes up bad merge * Extract common code and clean up Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix up CHANGELOG problems Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com * Fix up CHANGELOG problems Enact-DCO-1.0-Signed-off-by: Roy Sutton roy.sutton@lge.com QA-Reviewed-By: Jeff Lam (jeff.lam@lge.com) Reviewed-By: Stephen Choi (stephen.choi@lge.com) Integrated-By: Aaron Tam (aaron.tam@lge.com)
1 parent c1de04f commit 9f96386

File tree

9 files changed

+139
-37
lines changed

9 files changed

+139
-37
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The following is a curated list of changes in the Enact project, newest changes
2222
- `spotlight` to handle non-5-way keys correctly to focus on next 5-way keys
2323
- `spotlight/Spottable` to forward `onMouseEnter` and `onMouseLeave`
2424
- `ui/Remeasurable` to update on every trigger change
25-
- `ui/Transition` to revert 1.12.1 change to support `clip` transition-type directions and endering optimizations
25+
- `ui/Transition` to revert 1.12.1 change to support `clip` transition-type directions and rendering optimizations
2626

2727
## [1.12.1] - 2017-11-07
2828

packages/moonstone/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ The following is a curated list of changes in the Enact moonstone module, newest
1111
### Fixed
1212

1313
- `moonstone/Expandable` and derivatives to use the new `ease-out-quart` animation timing function to better match the aesthetic of Enyo's Expandables
14+
- `moonstone/LabeledItem` to start marquee when hovering over in disabled state
15+
- `moonstone/Marquee` to correctly start when hovering on disabled spottable components
16+
- `moonstone/Marquee.MarqueeController` to not abort marquee when moving among components
17+
- `moonstone/Picker` marquee issues with disabled buttons or Picker
18+
- `moonstone/Panels` to prevent loss of spotlight issue when moving between panels
1419

1520
## [1.12.2] - 2017-11-15
1621

packages/moonstone/LabeledItem/LabeledItem.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ const LabeledItemBase = kind({
4141
*/
4242
children: PropTypes.node.isRequired,
4343

44+
/**
45+
* When `true`, applies a disabled style and the control becomes non-interactive.
46+
*
47+
* @type {Boolean}
48+
* @public
49+
*/
50+
disabled: PropTypes.bool,
51+
4452
/**
4553
* The label to be displayed along with the text.
4654
*
@@ -63,13 +71,13 @@ const LabeledItemBase = kind({
6371
className: 'labeleditem'
6472
},
6573

66-
render: ({children, label, titleIcon, ...rest}) => (
67-
<Controller {...rest}>
74+
render: ({children, disabled, label, titleIcon, ...rest}) => (
75+
<Controller disabled={disabled} {...rest}>
6876
<div className={css.text}>
69-
<MarqueeText className={css.title}>{children}</MarqueeText>
77+
<MarqueeText disabled={disabled} className={css.title}>{children}</MarqueeText>
7078
{(titleIcon != null) ? <Icon small className={css.icon}>{titleIcon}</Icon> : null}
7179
</div>
72-
{(label != null) ? <MarqueeText className={css.label}>{label}</MarqueeText> : null}
80+
{(label != null) ? <MarqueeText disabled={disabled} className={css.label}>{label}</MarqueeText> : null}
7381
</Controller>
7482
)
7583
});

packages/moonstone/LabeledItem/tests/LabeledItem-specs.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import {mount} from 'enzyme';
2+
import {mount, shallow} from 'enzyme';
33

44
import LabeledItem from '../LabeledItem';
55
import css from '../LabeledItem.less';
@@ -44,7 +44,7 @@ describe('LabeledItem Specs', () => {
4444
});
4545

4646
it('should have \'disabled\' HTML attribute when \'disabled=true\'', function () {
47-
const item = mount(
47+
const item = shallow(
4848
<LabeledItem disabled>I am a disabled labeledItem</LabeledItem>
4949
);
5050

packages/moonstone/Marquee/MarqueeController.js

+58-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {forward} from '@enact/core/handle';
22
import hoc from '@enact/core/hoc';
3+
import {Job} from '@enact/core/util';
34
import React from 'react';
45
import PropTypes from 'prop-types';
56

@@ -33,6 +34,22 @@ const contextTypes = {
3334
*/
3435
complete: PropTypes.func,
3536

37+
/**
38+
* Called by Marquee instances when hovered
39+
*
40+
* @type {Function}
41+
* @memberof moonstone/Marquee.Marquee.contextTypes
42+
*/
43+
enter: PropTypes.func,
44+
45+
/**
46+
* Called by Marquee instances when unhovered
47+
*
48+
* @type {Function}
49+
* @memberof moonstone/Marquee.Marquee.contextTypes
50+
*/
51+
leave: PropTypes.func,
52+
3653
/**
3754
* Called to register a Marquee instance to be synchronized
3855
*
@@ -111,12 +128,20 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
111128
return {
112129
cancel: this.handleCancel,
113130
complete: this.handleComplete,
131+
enter: this.handleEnter,
132+
leave: this.handleLeave,
114133
register: this.handleRegister,
115134
start: this.handleStart,
116135
unregister: this.handleUnregister
117136
};
118137
}
119138

139+
componentWillUnmount () {
140+
this.cancelJob.stop();
141+
}
142+
143+
cancelJob = new Job(() => this.doCancel(), 30)
144+
120145
/*
121146
* Registers `component` with a set of handlers for `start` and `stop`.
122147
*
@@ -169,6 +194,7 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
169194
* @returns {undefined}
170195
*/
171196
handleStart = (component) => {
197+
this.cancelJob.stop();
172198
if (!this.anyRunning()) {
173199
this.markAll(STATE.ready);
174200
this.dispatch('start', component);
@@ -182,9 +208,16 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
182208
*
183209
* @returns {undefined}
184210
*/
185-
handleCancel = (component) => {
211+
handleCancel = () => {
212+
this.cancelJob.start();
213+
}
214+
215+
doCancel = () => {
216+
if (this.isHovered || this.isFocused) {
217+
return;
218+
}
186219
this.markAll(STATE.inactive);
187-
this.dispatch('stop', component);
220+
this.dispatch('stop');
188221
}
189222

190223
/*
@@ -197,17 +230,34 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
197230
handleComplete = (component) => {
198231
const complete = this.markReady(component);
199232
if (complete) {
233+
this.cancelJob.stop();
200234
this.markAll(STATE.ready);
201235
this.dispatch('start');
202236
}
203237
}
204238

239+
handleEnter = () => {
240+
this.isHovered = true;
241+
if (!this.anyRunning()) {
242+
this.dispatch('start');
243+
}
244+
this.cancelJob.stop();
245+
}
246+
247+
handleLeave = () => {
248+
this.isHovered = false;
249+
this.cancelJob.start();
250+
}
251+
205252
/*
206253
* Handler for the focus event
207254
*/
208255
handleFocus = (ev) => {
209256
this.isFocused = true;
210-
this.dispatch('start');
257+
if (!this.anyRunning()) {
258+
this.dispatch('start');
259+
}
260+
this.cancelJob.stop();
211261
forwardFocus(ev, this.props);
212262
}
213263

@@ -216,8 +266,7 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
216266
*/
217267
handleBlur = (ev) => {
218268
this.isFocused = false;
219-
this.dispatch('stop');
220-
this.markAll(STATE.inactive);
269+
this.cancelJob.start();
221270
forwardBlur(ev, this.props);
222271
}
223272

@@ -312,7 +361,10 @@ const MarqueeController = hoc(defaultConfig, (config, Wrapped) => {
312361
props = {
313362
...this.props,
314363
onBlur: this.handleBlur,
315-
onFocus: this.handleFocus
364+
onFocus: this.handleFocus,
365+
// When picker button becomes disabled, it doesn't fire blur, but does fire
366+
// `onSpotlightDisappear`. We should investigate why `onBlur` does not fire
367+
onSpotlightDisappear: this.handleBlur
316368
};
317369
}
318370

packages/moonstone/Marquee/MarqueeDecorator.js

+33-21
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
299299
this.textDirectionValidated = false;
300300
} else if (next.marqueeOn !== marqueeOn || next.marqueeDisabled !== marqueeDisabled || next.marqueeSpeed !== marqueeSpeed) {
301301
this.cancelAnimation();
302+
} else if (next.disabled && this.isHovered && marqueeOn === 'focus' && this.sync) {
303+
this.context.enter(this);
302304
}
303305
}
304306

@@ -372,7 +374,8 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
372374
this.forceRestartMarquee ||
373375
!this.sync && (
374376
(this.isFocused && this.props.marqueeOn === 'focus') ||
375-
(this.isHovered && this.props.marqueeOn === 'hover')
377+
(this.isHovered && this.props.marqueeOn === 'hover') ||
378+
(this.isHovered && this.props.marqueeOn === 'focus' && this.props.disabled)
376379
)
377380
);
378381
}
@@ -537,15 +540,17 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
537540
if (this.sync) {
538541
this.context.complete(this);
539542
} else {
540-
this.setState((prevState) => {
541-
if (!prevState.animating) {
542-
this.startAnimation();
543-
}
544-
return null;
545-
});
543+
this.setState(this.setStateStartAnimation);
546544
}
547545
}
548546

547+
setStateStartAnimation = (prevState) => {
548+
if (!prevState.animating) {
549+
this.startAnimation();
550+
}
551+
return null;
552+
}
553+
549554
/*
550555
* Resets and restarts the marquee after `marqueeResetDelay` milliseconds
551556
*
@@ -568,6 +573,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
568573
cancelAnimation = () => {
569574
if (this.sync) {
570575
this.context.cancel(this);
576+
return;
571577
}
572578

573579
this.stop();
@@ -592,35 +598,41 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
592598

593599
handleFocus = (ev) => {
594600
this.isFocused = true;
595-
this.setState((prevState) => {
596-
if (!prevState.animating) {
597-
this.startAnimation();
598-
}
599-
return null;
600-
});
601+
if (!this.sync) {
602+
this.setState(this.setStateStartAnimation);
603+
}
601604
forwardFocus(ev, this.props);
602605
}
603606

604607
handleBlur = (ev) => {
605608
this.isFocused = false;
606-
this.cancelAnimation();
609+
if (!this.sync) {
610+
this.cancelAnimation();
611+
}
607612
forwardBlur(ev, this.props);
608613
}
609614

610615
handleEnter = (ev) => {
611616
this.isHovered = true;
612-
this.setState((prevState) => {
613-
if (!prevState.animating) {
614-
this.startAnimation();
617+
if (this.props.disabled || this.props.marqueeOn === 'hover') {
618+
if (this.sync) {
619+
this.context.enter(this);
620+
} else {
621+
this.setState(this.setStateStartAnimation);
615622
}
616-
return null;
617-
});
623+
}
618624
forwardEnter(ev, this.props);
619625
}
620626

621627
handleLeave = (ev) => {
622628
this.isHovered = false;
623-
this.cancelAnimation();
629+
if (this.props.disabled || this.props.marqueeOn === 'hover') {
630+
if (this.sync) {
631+
this.context.leave(this);
632+
} else {
633+
this.cancelAnimation();
634+
}
635+
}
624636
forwardLeave(ev, this.props);
625637
}
626638

@@ -669,7 +681,7 @@ const MarqueeDecorator = hoc(defaultConfig, (config, Wrapped) => {
669681
}
670682

671683
// TODO: cancel others on hover
672-
if (marqueeOnHover || (disabled && marqueeOnFocus)) {
684+
if (marqueeOnHover || marqueeOnFocus) {
673685
rest[enter] = this.handleEnter;
674686
rest[leave] = this.handleLeave;
675687
}

packages/moonstone/internal/Picker/Picker.less

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
border-width: 0;
9494
border-style: solid;
9595
border-radius: inherit;
96+
pointer-events: none;
9697
}
9798

9899
.icon {

packages/moonstone/internal/Picker/PickerButton.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import Holdable from '../Holdable';
1+
import {forward, handle} from '@enact/core/handle';
22
import kind from '@enact/core/kind';
33
import React from 'react';
44
import PropTypes from 'prop-types';
55
import Pure from '@enact/ui/internal/Pure';
66

7+
import {contextTypes} from '../../Marquee/MarqueeController';
8+
import Holdable from '../Holdable';
79
import Icon from '../../Icon';
810
import IconButton from '../../IconButton';
911
import {withSkinnableProps} from '../../Skinnable';
@@ -26,10 +28,31 @@ const PickerButtonBase = kind({
2628
spotlightDisabled: PropTypes.bool
2729
},
2830

31+
contextTypes: contextTypes,
32+
2933
styles: {
3034
css
3135
},
3236

37+
handlers: {
38+
onMouseEnter: handle(
39+
forward('onMouseEnter'),
40+
(ev, props, context) => {
41+
if (context.enter) {
42+
context.enter(null);
43+
}
44+
}
45+
),
46+
onMouseLeave: handle(
47+
forward('onMouseLeave'),
48+
(ev, props, context) => {
49+
if (context.leave) {
50+
context.leave(null);
51+
}
52+
}
53+
)
54+
},
55+
3356
computed: {
3457
className: ({hidden, styler}) => styler.append({
3558
hidden

packages/ui/CHANGELOG.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ The following is a curated list of changes in the Enact ui module, newest change
1212

1313
### Fixed
1414

15+
- `ui/ViewManager` to prevent interaction issue with `moonstone/Scroller`
16+
1517
## [1.12.2] - 2017-11-15
1618

1719
### Fixed
18-
- `ui/Viewport` to blur Spotlight `onWillTransition`
19-
- `ui/View` use `idleUntil` to prevent wheel blocking error
2020

2121
- `ui/Remeasurable` to update on every trigger change
22+
- `ui/Transition` to revert 1.12.1 change to support `clip` transition-type directions and rendering optimizations
2223

2324
## [1.12.1] - 2017-11-07
2425

0 commit comments

Comments
 (0)