@uifabric/experiments
Version:
Experimental React components for building experiences for Microsoft 365.
295 lines • 15.4 kB
JavaScript
define(["require", "exports", "tslib", "react", "./FloatingSuggestions.scss", "office-ui-fabric-react/lib/Utilities", "office-ui-fabric-react/lib/Callout", "./Suggestions/SuggestionsControl"], function (require, exports, tslib_1, React, styles, Utilities_1, Callout_1, SuggestionsControl_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var FloatingSuggestions = /** @class */ (function (_super) {
tslib_1.__extends(FloatingSuggestions, _super);
function FloatingSuggestions(basePickerProps) {
var _this = _super.call(this, basePickerProps) || this;
_this.root = React.createRef();
_this.suggestionsControl = React.createRef();
_this.isComponentMounted = false;
_this.onQueryStringChanged = function (queryString) {
if (queryString !== _this.state.queryString) {
_this.setState({
queryString: queryString,
});
if (_this.props.onInputChanged) {
_this.props.onInputChanged(queryString);
}
_this.updateValue(queryString);
}
};
_this.hidePicker = function () {
if (_this.props.onSuggestionsHidden && _this.isSuggestionsShown) {
_this.props.onSuggestionsHidden();
}
_this.setState({
suggestionsVisible: false,
});
};
_this.showPicker = function (updateValue) {
if (updateValue === void 0) { updateValue = false; }
if (_this.props.onSuggestionsShown && !_this.isSuggestionsShown) {
_this.props.onSuggestionsShown();
}
_this.setState({
suggestionsVisible: true,
});
// Update the suggestions if updateValue == true
var value = _this.props.inputElement ? _this.props.inputElement.value : '';
if (updateValue) {
_this.updateValue(value);
}
};
_this.onCurrentlySelectedSuggestionChosen = function () {
if (_this.suggestionsControl.current && _this.suggestionsControl.current.hasSuggestionSelected()) {
_this._onSuggestionSelected(_this.suggestionsControl.current.currentSuggestion.item);
}
};
_this._onSuggestionClick = function (ev, item, index) {
_this._onSuggestionSelected(item);
_this._updateSuggestionsVisible(false /*shouldShow*/);
};
_this._onSuggestionRemove = function (ev, item, index) {
if (_this.props.onRemoveSuggestion) {
_this.props.onRemoveSuggestion(item);
}
if (_this.suggestionsControl.current) {
_this.suggestionsControl.current.removeSuggestion(index);
}
};
_this._onKeyDown = function (ev) {
if (!_this.state.suggestionsVisible ||
(_this.props.inputElement && ev.target instanceof Node && !_this.props.inputElement.contains(ev.target))) {
return;
}
// eslint-disable-next-line deprecation/deprecation
var keyCode = ev.which;
switch (keyCode) {
case Utilities_1.KeyCodes.escape:
_this.hidePicker();
ev.preventDefault();
ev.stopPropagation();
break;
case Utilities_1.KeyCodes.tab:
case Utilities_1.KeyCodes.enter:
if (!ev.shiftKey &&
!ev.ctrlKey &&
_this.suggestionsControl.current &&
_this.suggestionsControl.current.handleKeyDown(keyCode)) {
ev.preventDefault();
ev.stopPropagation();
}
else {
// no selection. Try to force resolve the current query
_this._validateAndInsertCurrentQueryString();
}
break;
case Utilities_1.KeyCodes.del:
if (_this.props.onRemoveSuggestion &&
_this.suggestionsControl.current &&
_this.suggestionsControl.current.hasSuggestionSelected &&
_this.suggestionsControl.current.currentSuggestion &&
ev.shiftKey) {
_this.props.onRemoveSuggestion(_this.suggestionsControl.current.currentSuggestion.item);
_this.suggestionsControl.current.removeSuggestion();
_this.forceUpdate();
ev.stopPropagation();
}
break;
case Utilities_1.KeyCodes.up:
if (_this.suggestionsControl.current && _this.suggestionsControl.current.handleKeyDown(keyCode)) {
ev.preventDefault();
ev.stopPropagation();
_this._updateActiveDescendant();
}
break;
case Utilities_1.KeyCodes.down:
if (_this.suggestionsControl.current && _this.suggestionsControl.current.handleKeyDown(keyCode)) {
ev.preventDefault();
ev.stopPropagation();
_this._updateActiveDescendant();
}
break;
}
};
_this._validateAndInsertCurrentQueryString = function () {
if (_this.state.queryString && _this.props.isQueryForceResolveable && _this.props.createForceResolvedItem) {
var isForceResolvable = _this.props.isQueryForceResolveable(_this.state.queryString);
if (!isForceResolvable) {
return;
}
var itemToConvert = _this.props.createForceResolvedItem(_this.state.queryString);
var convertedItems = _this.suggestionStore.convertSuggestionsToSuggestionItems([itemToConvert]);
_this._onSuggestionSelected(convertedItems[0].item);
}
};
_this._async = new Utilities_1.Async(_this);
Utilities_1.initializeComponentRef(_this);
_this.suggestionStore = basePickerProps.suggestionsStore;
_this.state = {
queryString: '',
didBind: false,
};
return _this;
}
Object.defineProperty(FloatingSuggestions.prototype, "inputText", {
// TODO FloatingSuggestions should not be responsible for getting the
// input text.
get: function () {
return this.state.queryString;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FloatingSuggestions.prototype, "suggestions", {
get: function () {
return this.suggestionStore.suggestions;
},
enumerable: true,
configurable: true
});
FloatingSuggestions.prototype.forceResolveSuggestion = function () {
if (this.suggestionsControl.current && this.suggestionsControl.current.hasSuggestionSelected()) {
this.onCurrentlySelectedSuggestionChosen();
}
else {
this._validateAndInsertCurrentQueryString();
}
};
Object.defineProperty(FloatingSuggestions.prototype, "currentSelectedSuggestionIndex", {
get: function () {
return this.suggestionsControl.current ? this.suggestionsControl.current.currentSuggestionIndex : -1;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FloatingSuggestions.prototype, "isSuggestionsShown", {
get: function () {
return this.state.suggestionsVisible === undefined ? false : this.state.suggestionsVisible;
},
enumerable: true,
configurable: true
});
FloatingSuggestions.prototype.componentDidMount = function () {
this._bindToInputElement();
this.isComponentMounted = true;
this._onResolveSuggestions = this._async.debounce(this._onResolveSuggestions, this.props.resolveDelay);
};
FloatingSuggestions.prototype.componentDidUpdate = function () {
this._bindToInputElement();
};
FloatingSuggestions.prototype.componentWillUnmount = function () {
this._unbindFromInputElement();
this.isComponentMounted = false;
this._async.dispose();
};
FloatingSuggestions.prototype.UNSAFE_componentWillReceiveProps = function (newProps) {
if (newProps.suggestionItems) {
this.updateSuggestions(newProps.suggestionItems);
}
};
FloatingSuggestions.prototype.updateSuggestions = function (suggestions, forceUpdate) {
if (forceUpdate === void 0) { forceUpdate = false; }
this.suggestionStore.updateSuggestions(suggestions);
if (forceUpdate) {
this.forceUpdate();
}
};
FloatingSuggestions.prototype.render = function () {
var className = this.props.className;
return (React.createElement("div", { ref: this.root, className: Utilities_1.css('ms-BasePicker ms-BaseFloatingPicker', className ? className : '') }, this._renderSuggestions()));
};
FloatingSuggestions.prototype.updateValue = function (updatedValue) {
if (updatedValue === '') {
this.updateSuggestionWithZeroState();
}
else {
this._onResolveSuggestions(updatedValue);
}
};
FloatingSuggestions.prototype.updateSuggestionWithZeroState = function () {
if (this.props.onZeroQuerySuggestion) {
var suggestions = this.props.onZeroQuerySuggestion();
this.updateSuggestionsList(suggestions || []);
}
else {
this.hidePicker();
}
};
FloatingSuggestions.prototype.updateSuggestionsList = function (suggestions) {
var _this = this;
// Check to see if the returned value is an array, if it is then just pass it into the next function.
// If the returned value is not an array then check to see if it's a promise or PromiseLike.
// If it is then resolve it asynchronously.
if (Array.isArray(suggestions)) {
this.updateSuggestions(suggestions, true /*forceUpdate*/);
}
else if (suggestions && suggestions.then) {
// Ensure that the promise will only use the callback if it was the most recent one.
var promise_1 = (this.currentPromise = suggestions);
promise_1.then(function (newSuggestions) {
// Only update if the next promise has not yet resolved and
// the floating picker is still mounted.
if (promise_1 === _this.currentPromise && _this.isComponentMounted) {
_this.updateSuggestions(newSuggestions, true /*forceUpdate*/);
}
});
}
};
FloatingSuggestions.prototype._renderSuggestions = function () {
// Express this as 2 separate statements instead of a single one, because `undefined` isn't filtered out of the type
// when using `|| SuggestionsControl`
var TypedSuggestionsControl = this
.props.onRenderSuggestionControl;
if (TypedSuggestionsControl === undefined) {
TypedSuggestionsControl = SuggestionsControl_1.SuggestionsControl;
}
return this.state.suggestionsVisible ? (React.createElement(Callout_1.Callout, { className: styles.callout, isBeakVisible: false, gapSpace: 5, target: this.props.inputElement, onDismiss: this.hidePicker, directionalHint: Callout_1.DirectionalHint.bottomLeftEdge, directionalHintForRTL: Callout_1.DirectionalHint.bottomRightEdge, calloutWidth: this.props.calloutWidth ? this.props.calloutWidth : 0 },
React.createElement(TypedSuggestionsControl, { onRenderSuggestion: this.props.onRenderSuggestionsItem, onSuggestionClick: this._onSuggestionClick, onSuggestionRemove: this._onSuggestionRemove, suggestions: this.suggestionStore.getSuggestions(), componentRef: this.suggestionsControl, onCurrentlySelectedSuggestionChosen: this.onCurrentlySelectedSuggestionChosen, shouldLoopSelection: false }))) : null;
};
FloatingSuggestions.prototype._onSuggestionSelected = function (item) {
if (this.props.onSuggestionSelected) {
this.props.onSuggestionSelected(item);
}
};
FloatingSuggestions.prototype._updateActiveDescendant = function () {
if (this.props.inputElement && this.suggestionsControl.current && this.suggestionsControl.current.selectedElement) {
var selectedElId = this.suggestionsControl.current.selectedElement.getAttribute('id');
if (selectedElId) {
this.props.inputElement.setAttribute('aria-activedescendant', selectedElId);
}
}
};
FloatingSuggestions.prototype._onResolveSuggestions = function (updatedValue) {
var suggestions = this.props.onResolveSuggestions(updatedValue);
this._updateSuggestionsVisible(true /*shouldShow*/);
if (suggestions !== null) {
this.updateSuggestionsList(suggestions);
}
};
FloatingSuggestions.prototype._updateSuggestionsVisible = function (shouldShow) {
if (shouldShow) {
this.showPicker();
}
else {
this.hidePicker();
}
};
FloatingSuggestions.prototype._bindToInputElement = function () {
if (this.props.inputElement && !this.state.didBind) {
this.props.inputElement.addEventListener('keydown', this._onKeyDown);
this.setState({ didBind: true });
}
};
FloatingSuggestions.prototype._unbindFromInputElement = function () {
if (this.props.inputElement && this.state.didBind) {
this.props.inputElement.removeEventListener('keydown', this._onKeyDown);
this.setState({ didBind: false });
}
};
return FloatingSuggestions;
}(React.Component));
exports.FloatingSuggestions = FloatingSuggestions;
});
//# sourceMappingURL=FloatingSuggestions.js.map