Skip to content

Commit ce85e0e

Browse files
Merge pull request salesforce#1646 from kevinparkerson/disable-increment-decrement-min-max-counter
Disable increment/decrement when min/max is hit
2 parents 5db8541 + 79e228d commit ce85e0e

File tree

3 files changed

+90
-28
lines changed

3 files changed

+90
-28
lines changed

components/component-docs.json

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4423,6 +4423,18 @@
44234423
"params": [],
44244424
"returns": null
44254425
},
4426+
{
4427+
"name": "getInputProps",
4428+
"docblock": null,
4429+
"modifiers": [],
4430+
"params": [
4431+
{
4432+
"name": "{ assistiveText, labels }",
4433+
"type": null
4434+
}
4435+
],
4436+
"returns": null
4437+
},
44264438
{
44274439
"name": "setInputRef",
44284440
"docblock": null,
@@ -4579,13 +4591,6 @@
45794591
"computed": false
45804592
}
45814593
},
4582-
"children": {
4583-
"type": {
4584-
"name": "node"
4585-
},
4586-
"required": false,
4587-
"description": "Pass in an `<Input />` component to customize it. Event handlers for the input (if needed) should be added here and not to this component. `<Input onKeyDown... />`.` _Tested with Mocha framework._"
4588-
},
45894594
"className": {
45904595
"type": {
45914596
"name": "union",
@@ -4691,6 +4696,13 @@
46914696
"computed": false
46924697
}
46934698
},
4699+
"input": {
4700+
"type": {
4701+
"name": "node"
4702+
},
4703+
"required": false,
4704+
"description": "A [Dropdown](http://react.lightningdesignsystem.com/components/inputs/) component. The props from this `Input` component will be merged and override any default props. See [Component composition with prop spread](https://github.com/salesforce/design-system-react/blob/master/docs/codebase-overview.md#component-composition-with-prop-spread) for more information on this methodology."
4705+
},
46944706
"isOpen": {
46954707
"type": {
46964708
"name": "bool"
@@ -4763,14 +4775,14 @@
47634775
"name": "func"
47644776
},
47654777
"required": false,
4766-
"description": "Function called when the calendar dialog would like hide. This will turn the calendar dialog into a controlled component. Please use with `isOpen`. _Tested with Mocha framework._"
4778+
"description": "Function called when the calendar dialog would like hide. This will turn the calendar dialog into into a controlled component. Please use with `isOpen`. _Tested with Mocha framework._"
47674779
},
47684780
"onRequestOpen": {
47694781
"type": {
47704782
"name": "func"
47714783
},
47724784
"required": false,
4773-
"description": "Function called when the calendar dialog would like show. This will turn the calendar dialog into a controlled component. Please use with `isOpen`. _Tested with Mocha framework._"
4785+
"description": "Function called when the calendar dialog would like show. This will turn the calendar dialog into into a controlled component. Please use with `isOpen`. _Tested with Mocha framework._"
47744786
},
47754787
"parser": {
47764788
"type": {
@@ -5082,6 +5094,13 @@
50825094
"params": [],
50835095
"returns": null
50845096
},
5097+
{
5098+
"name": "getValueAsNumber",
5099+
"docblock": null,
5100+
"modifiers": [],
5101+
"params": [],
5102+
"returns": null
5103+
},
50855104
{
50865105
"name": "getCounterButtonIcon",
50875106
"docblock": null,
@@ -5149,6 +5168,13 @@
51495168
}
51505169
],
51515170
"returns": null
5171+
},
5172+
{
5173+
"name": "stopStepping",
5174+
"docblock": null,
5175+
"modifiers": [],
5176+
"params": [],
5177+
"returns": null
51525178
}
51535179
],
51545180
"props": {

components/input/__tests__/input.browser-test.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,13 @@ describe('SLDSInput', () => {
603603
TestUtils.Simulate.mouseDown(increment);
604604
TestUtils.Simulate.mouseUp(increment);
605605
expect(changeOccurred).to.be.false;
606+
expect(increment.disabled).to.be.true;
606607

607608
changeOccurred = false;
608609
TestUtils.Simulate.mouseDown(decrement);
609610
TestUtils.Simulate.mouseUp(decrement);
610611
expect(changeOccurred).to.be.false;
612+
expect(decrement.disabled).to.be.true;
611613
});
612614

613615
it('acknowledges custom step values', () => {

components/input/index.jsx

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,33 @@ class Input extends React.Component {
327327

328328
getErrorId = () => this.props['aria-describedby'] || this.generatedErrorId;
329329

330+
getValueAsNumber = () => {
331+
let value = 0;
332+
333+
if (this.props.value !== undefined) {
334+
value = Number(this.props.value);
335+
} else if (this.inputRef) {
336+
value = Number(this.inputRef.value);
337+
}
338+
339+
return value;
340+
};
341+
330342
getCounterButtonIcon = (direction) => {
331-
const stopStepping = () => {
332-
clearTimeout(this.stepping.timeout);
333-
this.stepping.currentDelay = this.stepping.initialDelay;
334-
};
343+
const value = this.getValueAsNumber();
344+
let disabled = false;
345+
346+
if (
347+
this.props.disabled ||
348+
(direction === INCREMENT &&
349+
this.props.maxValue !== undefined &&
350+
value >= this.props.maxValue) ||
351+
(direction === DECREMENT &&
352+
this.props.minValue !== undefined &&
353+
value <= this.props.minValue)
354+
) {
355+
disabled = true;
356+
}
335357

336358
return (
337359
<Button
@@ -342,20 +364,20 @@ class Input extends React.Component {
342364
'slds-button_icon-small',
343365
`slds-input__button_${direction.toLowerCase()}`
344366
)}
345-
disabled={this.props.disabled}
367+
disabled={disabled}
346368
iconCategory="utility"
347369
iconName={direction === DECREMENT ? 'ban' : 'new'}
348370
onKeyDown={(event) => {
349371
if (event.keyCode === 13) {
350372
this.performStep(direction, event);
351373
}
352374
}}
353-
onKeyUp={stopStepping}
375+
onKeyUp={this.stopStepping}
354376
onMouseDown={(event) => {
355377
this.performStep(direction, event);
356378
}}
357-
onMouseLeave={stopStepping}
358-
onMouseUp={stopStepping}
379+
onMouseLeave={this.stopStepping}
380+
onMouseUp={this.stopStepping}
359381
variant="icon"
360382
/>
361383
);
@@ -431,15 +453,9 @@ class Input extends React.Component {
431453
const maxValue = this.props.maxValue;
432454
const minValue = this.props.minValue;
433455
const step = this.props.step !== undefined ? Number(this.props.step) : 1;
434-
let value = 0;
456+
let value = this.getValueAsNumber();
435457
let valueChanged = false;
436458

437-
if (this.props.value !== undefined) {
438-
value = Number(this.props.value);
439-
} else if (this.inputRef) {
440-
value = Number(this.inputRef.value);
441-
}
442-
443459
if (direction === DECREMENT && maxValue !== undefined && value > maxValue) {
444460
value = Number(maxValue);
445461
valueChanged = true;
@@ -481,8 +497,12 @@ class Input extends React.Component {
481497
}
482498

483499
if (valueChanged) {
500+
/*
501+
* Use of `this.forceUpdate` is an anti-pattern. This code only executes if this `input` element is uncontrolled which this library believes is an anti-pattern, also. This code is only present to allow for the edge case of uncontrolled use of an `input`.
502+
*/
484503
if (this.props.value === undefined && this.inputRef) {
485504
this.inputRef.value = String(value);
505+
this.forceUpdate();
486506
} else if (this.props.onChange) {
487507
this.props.onChange(event, {
488508
number: value,
@@ -491,10 +511,24 @@ class Input extends React.Component {
491511
}
492512
}
493513

494-
this.stepping.timeout = setTimeout(() => {
495-
this.stepping.currentDelay = this.stepping.speedDelay;
496-
this.performStep(direction);
497-
}, this.stepping.currentDelay);
514+
if (
515+
(direction === INCREMENT &&
516+
maxValue !== undefined &&
517+
value >= maxValue) ||
518+
(direction === DECREMENT && minValue !== undefined && value <= minValue)
519+
) {
520+
this.stopStepping();
521+
} else {
522+
this.stepping.timeout = setTimeout(() => {
523+
this.stepping.currentDelay = this.stepping.speedDelay;
524+
this.performStep(direction);
525+
}, this.stepping.currentDelay);
526+
}
527+
};
528+
529+
stopStepping = () => {
530+
clearTimeout(this.stepping.timeout);
531+
this.stepping.currentDelay = this.stepping.initialDelay;
498532
};
499533

500534
render() {

0 commit comments

Comments
 (0)