office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
271 lines • 12.6 kB
JavaScript
import * as tslib_1 from "tslib";
import * as React from 'react';
import { BaseComponent, getNativeProps, inputProperties, createRef } from '../../Utilities';
var SELECTION_FORWARD = 'forward';
var SELECTION_BACKWARD = 'backward';
var Autofill = /** @class */ (function (_super) {
tslib_1.__extends(Autofill, _super);
function Autofill(props) {
var _this = _super.call(this, props) || this;
_this._inputElement = createRef();
_this._autoFillEnabled = true;
// Composition events are used when the character/text requires several keystrokes to be completed.
// Some examples of this are mobile text input and langauges like Japanese or Arabic.
// Find out more at https://developer.mozilla.org/en-US/docs/Web/Events/compositionstart
_this._onCompositionStart = function (ev) {
_this._autoFillEnabled = false;
};
// Composition events are used when the character/text requires several keystrokes to be completed.
// Some examples of this are mobile text input and langauges like Japanese or Arabic.
// Find out more at https://developer.mozilla.org/en-US/docs/Web/Events/compositionstart
_this._onCompositionEnd = function (ev) {
var inputValue = _this._getCurrentInputValue();
_this._tryEnableAutofill(inputValue, _this.value, false, true);
// Due to timing, this needs to be async, otherwise no text will be selected.
_this._async.setTimeout(function () { return _this._updateValue(inputValue); }, 0);
};
_this._onClick = function () {
if (_this._value && _this._value !== '' && _this._autoFillEnabled) {
_this._autoFillEnabled = false;
}
};
_this._onKeyDown = function (ev) {
if (_this.props.onKeyDown) {
_this.props.onKeyDown(ev);
}
// If the event is actively being composed, then don't alert autofill.
// Right now typing does not have isComposing, once that has been fixed any should be removed.
if (!ev.nativeEvent.isComposing) {
switch (ev.which) {
case 8 /* backspace */:
_this._autoFillEnabled = false;
break;
case 37 /* left */:
case 39 /* right */:
if (_this._autoFillEnabled) {
_this._value = _this.state.displayValue;
_this._autoFillEnabled = false;
}
break;
default:
if (!_this._autoFillEnabled) {
if (_this.props.enableAutofillOnKeyPress.indexOf(ev.which) !== -1) {
_this._autoFillEnabled = true;
}
}
break;
}
}
};
_this._onInputChanged = function (ev) {
var value = _this._getCurrentInputValue(ev);
// Right now typing does not have isComposing, once that has been fixed any should be removed.
_this._tryEnableAutofill(value, _this._value, ev.nativeEvent.isComposing);
_this._updateValue(value);
};
_this._onChanged = function () {
// Swallow this event, we don't care about it
// We must provide it because React PropTypes marks it as required, but onInput serves the correct purpose
return;
};
/**
* Updates the current input value as well as getting a new display value.
* @param newValue The new value from the input
*/
_this._updateValue = function (newValue) {
// Only proceed if the value is nonempty and is different from the old value
// This is to work around the fact that, in IE 11, inputs with a placeholder fire an onInput event on focus
if (!newValue && newValue === _this._value) {
return;
}
_this._value = _this.props.onInputChange ? _this.props.onInputChange(newValue) : newValue;
_this.setState({
displayValue: _this._getDisplayValue(_this._value, _this.props.suggestedDisplayValue)
}, function () { return _this._notifyInputChange(_this._value); });
};
_this._value = props.defaultVisibleValue || '';
_this.state = {
displayValue: props.defaultVisibleValue || ''
};
return _this;
}
Object.defineProperty(Autofill.prototype, "cursorLocation", {
get: function () {
if (this._inputElement.current) {
var inputElement = this._inputElement.current;
if (inputElement.selectionDirection !== SELECTION_FORWARD) {
return inputElement.selectionEnd;
}
else {
return inputElement.selectionStart;
}
}
else {
return -1;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(Autofill.prototype, "isValueSelected", {
get: function () {
return Boolean(this.inputElement && this.inputElement.selectionStart !== this.inputElement.selectionEnd);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Autofill.prototype, "value", {
get: function () {
return this._value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Autofill.prototype, "selectionStart", {
get: function () {
return this._inputElement.current ? this._inputElement.current.selectionStart : -1;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Autofill.prototype, "selectionEnd", {
get: function () {
return this._inputElement.current ? this._inputElement.current.selectionEnd : -1;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Autofill.prototype, "inputElement", {
get: function () {
return this._inputElement.current;
},
enumerable: true,
configurable: true
});
Autofill.prototype.componentWillReceiveProps = function (nextProps) {
var newValue;
if (this.props.updateValueInWillReceiveProps) {
newValue = this.props.updateValueInWillReceiveProps();
}
newValue = this._getDisplayValue(newValue ? newValue : this._value, nextProps.suggestedDisplayValue);
if (typeof newValue === 'string') {
this.setState({ displayValue: newValue });
}
};
Autofill.prototype.componentDidUpdate = function () {
var value = this._value;
var _a = this.props, suggestedDisplayValue = _a.suggestedDisplayValue, shouldSelectFullInputValueInComponentDidUpdate = _a.shouldSelectFullInputValueInComponentDidUpdate;
var differenceIndex = 0;
if (this._autoFillEnabled &&
value &&
suggestedDisplayValue &&
this._doesTextStartWith(suggestedDisplayValue, value)) {
var shouldSelectFullRange = false;
if (shouldSelectFullInputValueInComponentDidUpdate) {
shouldSelectFullRange = shouldSelectFullInputValueInComponentDidUpdate();
}
if (shouldSelectFullRange && this._inputElement.current) {
this._inputElement.current.setSelectionRange(0, suggestedDisplayValue.length, SELECTION_BACKWARD);
}
else {
while (differenceIndex < value.length &&
value[differenceIndex].toLocaleLowerCase() === suggestedDisplayValue[differenceIndex].toLocaleLowerCase()) {
differenceIndex++;
}
if (differenceIndex > 0 && this._inputElement.current) {
this._inputElement.current.setSelectionRange(differenceIndex, suggestedDisplayValue.length, SELECTION_BACKWARD);
}
}
}
};
Autofill.prototype.render = function () {
var displayValue = this.state.displayValue;
var nativeProps = getNativeProps(this.props, inputProperties);
return (React.createElement("input", tslib_1.__assign({}, nativeProps, { ref: this._inputElement, value: displayValue, autoCapitalize: 'off', autoComplete: 'off', onCompositionStart: this._onCompositionStart, onCompositionEnd: this._onCompositionEnd, onChange: this._onChanged, onInput: this._onInputChanged, onKeyDown: this._onKeyDown, onClick: this.props.onClick ? this.props.onClick : this._onClick, "data-lpignore": true })));
};
Autofill.prototype.focus = function () {
this._inputElement.current && this._inputElement.current.focus();
};
Autofill.prototype.clear = function () {
this._autoFillEnabled = true;
this._updateValue('');
this._inputElement.current && this._inputElement.current.setSelectionRange(0, 0);
};
Autofill.prototype._getCurrentInputValue = function (ev) {
if (ev && ev.target && ev.target.value) {
return ev.target.value;
}
else if (this.inputElement && this.inputElement.value) {
return this.inputElement.value;
}
else {
return '';
}
};
/**
* Attempts to enable autofill. Whether or not autofill is enabled depends on the input value,
* whether or not any text is selected, and only if the new input value is longer than the old input value.
* Autofill should never be set to true if the value is composing. Once compositionEnd is called, then
* it should be completed.
* See https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent for more information on composition.
* @param newValue
* @param oldValue
* @param isComposing if true then the text is actively being composed and it has not completed.
* @param isComposed if the text is a composed text value.
*/
Autofill.prototype._tryEnableAutofill = function (newValue, oldValue, isComposing, isComposed) {
if (!isComposing &&
newValue &&
this._inputElement.current &&
this._inputElement.current.selectionStart === newValue.length &&
!this._autoFillEnabled &&
(newValue.length > oldValue.length || isComposed)) {
this._autoFillEnabled = true;
}
};
Autofill.prototype._notifyInputChange = function (newValue) {
if (this.props.onInputValueChange) {
this.props.onInputValueChange(newValue);
}
};
/**
* Returns a string that should be used as the display value.
* It evaluates this based on whether or not the suggested value starts with the input value
* and whether or not autofill is enabled.
* @param inputValue the value that the input currently has.
* @param suggestedDisplayValue the possible full value
*/
Autofill.prototype._getDisplayValue = function (inputValue, suggestedDisplayValue) {
var displayValue = inputValue;
if (suggestedDisplayValue &&
inputValue &&
this._doesTextStartWith(suggestedDisplayValue, displayValue) &&
this._autoFillEnabled) {
displayValue = suggestedDisplayValue;
}
return displayValue;
};
Autofill.prototype._doesTextStartWith = function (text, startWith) {
if (!text || !startWith) {
return false;
}
return text.toLocaleLowerCase().indexOf(startWith.toLocaleLowerCase()) === 0;
};
Autofill.defaultProps = {
enableAutofillOnKeyPress: [40 /* down */, 38 /* up */]
};
return Autofill;
}(BaseComponent));
export { Autofill };
/**
* Legacy, @deprecated, do not use.
*/
var BaseAutoFill = /** @class */ (function (_super) {
tslib_1.__extends(BaseAutoFill, _super);
function BaseAutoFill() {
return _super !== null && _super.apply(this, arguments) || this;
}
return BaseAutoFill;
}(Autofill));
export { BaseAutoFill };
//# sourceMappingURL=Autofill.js.map