UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

198 lines (197 loc) 14.3 kB
import { __assign, __extends } from "tslib"; import "../../CommonImports"; import "../../Core/core.css"; import "./TextField.css"; import * as React from "react"; import { FocusWithin } from '../../FocusWithin'; import { FocusZoneContext } from '../../FocusZone'; import { FormItemContext, Severity } from '../../FormItem'; import { Icon, IconSize } from '../../Icon'; import { Observer } from '../../Observer'; import { Tooltip } from '../../TooltipEx'; import { css, getSafeId, KeyCode } from '../../Util'; import { getTabIndex } from '../../Utilities/Focus'; import { TextFieldFocusTreatmentBehavior, TextFieldStyle, TextFieldWidth } from "./TextField.Props"; var inputId = 1; var TextField = /** @class */ (function (_super) { __extends(TextField, _super); function TextField(props) { var _this = _super.call(this, props) || this; _this.select = function () { if (_this.inputElement.current) { _this.inputElement.current.select(); } }; _this.getTextLength = function (value) { var _a; if (!value) { return 0; } else if (typeof value === "string") { return value.length; } else { return ((_a = value.value) === null || _a === void 0 ? void 0 : _a.length) || 0; } }; _this.inputId = "textfield-input-".concat(inputId++); _this.inputElement = props.inputElement || React.createRef(); _this.state = { textLength: props.showCharacterCounter ? _this.getTextLength(props.value) : 0 }; return _this; } TextField.prototype.focus = function () { if (this.inputElement.current) { this.inputElement.current.focus(); } }; Object.defineProperty(TextField.prototype, "selectionEnd", { get: function () { return this.inputElement.current ? this.inputElement.current.selectionEnd : null; }, enumerable: false, configurable: true }); Object.defineProperty(TextField.prototype, "selectionStart", { get: function () { return this.inputElement.current ? this.inputElement.current.selectionStart : null; }, enumerable: false, configurable: true }); TextField.prototype.setSelectionRange = function (start, end, direction) { if (this.inputElement.current) { this.inputElement.current.setSelectionRange(start, end, direction); } }; TextField.prototype.render = function () { var _this = this; var _a = this.props, autoAdjustHeight = _a.autoAdjustHeight, className = _a.className, containerClassName = _a.containerClassName, disabled = _a.disabled, _b = _a.focusTreatment, focusTreatment = _b === void 0 ? TextFieldFocusTreatmentBehavior.all : _b, inputId = _a.inputId, label = _a.label, onBlur = _a.onBlur, onFocus = _a.onFocus, onChange = _a.onChange, required = _a.required, style = _a.style, value = _a.value, width = _a.width; var localOnChange = function (event, newValue) { onChange && onChange(event, newValue); if (_this.props.maxLength && _this.props.showCharacterCounter) { _this.setState({ textLength: newValue.length }); } }; var input = (React.createElement(FocusWithin, { onFocus: onFocus, onBlur: onBlur }, function (focusStatus) { return (React.createElement(FormItemContext.Consumer, null, function (formItemContext) { return (React.createElement("div", { className: css("flex-column", containerClassName, width !== TextFieldWidth.auto && width) }, React.createElement("div", { className: css(!label && className, "bolt-textfield flex-row flex-center", disabled && "disabled", focusTreatment === TextFieldFocusTreatmentBehavior.all && "focus-treatment", focusTreatment === TextFieldFocusTreatmentBehavior.keyboardOnly && "focus-keyboard-only", focusStatus.hasFocus && "focused", style === TextFieldStyle.inline && "bolt-textfield-inline", formItemContext.error && (!formItemContext.severity || formItemContext.severity === Severity.Error) && "bolt-textfield-error", formItemContext.error && formItemContext.severity === Severity.Warning && "bolt-textfield-warning") }, React.createElement(FocusZoneContext.Consumer, null, function (zoneContext) { return (React.createElement(Observer, { value: value }, function (observedProps) { return (React.createElement(TextFieldInnerValue, __assign({}, _this.props, { onKeyDown: function (event) { var _a, _b; if (_this.props.multiline && event.keyCode === KeyCode.enter && !event.ctrlKey) { event.stopPropagation(); return; } (_b = (_a = _this.props).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, onChange: localOnChange, focus: function () { return _this.focus(); }, required: required, focusStatus: focusStatus, formItemContext: formItemContext, inputElement: _this.inputElement, inputId: _this.props.inputId || _this.inputId, value: observedProps.value, zoneContext: zoneContext }))); })); })), _this.props.maxLength && _this.props.showCharacterCounter && (React.createElement("div", { className: "bolt-textfield-counter" }, React.createElement("span", null, _this.state.textLength, "/", _this.props.maxLength))))); })); })); if (label) { return (React.createElement("div", { className: css(className, "flex-column") }, React.createElement("label", { htmlFor: getSafeId(inputId || this.inputId), className: required ? "bolt-textfield-label bolt-textfield-label--required" : "bolt-textfield-label" }, label), input)); } else { return input; } }; return TextField; }(React.Component)); export { TextField }; var TextFieldInnerValue = /** @class */ (function (_super) { __extends(TextFieldInnerValue, _super); function TextFieldInnerValue() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.adjustedHeight = -1; _this.adjustedHeightValue = ""; _this.hiddenElement = React.createRef(); return _this; } TextFieldInnerValue.prototype.render = function () { var _this = this; var _a = this.props, activatable = _a.activatable, ariaActiveDescendant = _a.ariaActiveDescendant, ariaAutoComplete = _a.ariaAutoComplete, ariaControls = _a.ariaControls, ariaExpanded = _a.ariaExpanded, ariaHasPopup = _a.ariaHasPopup, ariaInvalid = _a.ariaInvalid, ariaLabel = _a.ariaLabel, ariaLabelledBy = _a.ariaLabelledBy, ariaRoleDescription = _a.ariaRoleDescription, autoAdjustHeight = _a.autoAdjustHeight, autoComplete = _a.autoComplete, autoFocus = _a.autoFocus, autoSelect = _a.autoSelect, disabled = _a.disabled, excludeFocusZone = _a.excludeFocusZone, focus = _a.focus, focusStatus = _a.focusStatus, formItemContext = _a.formItemContext, inputClassName = _a.inputClassName, inputElement = _a.inputElement, inputId = _a.inputId, inputType = _a.inputType, maxLength = _a.maxLength, maxWidth = _a.maxWidth, multiline = _a.multiline, onClick = _a.onClick, onKeyDown = _a.onKeyDown, onKeyPress = _a.onKeyPress, onKeyUp = _a.onKeyUp, onPaste = _a.onPaste, placeholder = _a.placeholder, prefixIconProps = _a.prefixIconProps, readOnly = _a.readOnly, required = _a.required, resizable = _a.resizable, role = _a.role, rows = _a.rows, spellCheck = _a.spellCheck, tooltipProps = _a.tooltipProps, value = _a.value, zoneContext = _a.zoneContext; var _b = this.props, ariaDescribedBy = _b.ariaDescribedBy, suffixIconProps = _b.suffixIconProps; var TagName = multiline ? "textarea" : "input"; var tagSpecificProps = multiline ? { rows: rows } : { type: inputType, autoComplete: autoComplete ? "on" : "off" }; if (suffixIconProps === undefined && formItemContext.error) { if (formItemContext.severity === Severity.Warning) { suffixIconProps = { className: "bolt-textfield-message-warning", iconName: "Warning" }; } else { suffixIconProps = { className: "bolt-textfield-message-error", iconName: "Error" }; } } if (ariaDescribedBy === undefined) { ariaDescribedBy = formItemContext.ariaDescribedById; } var className = css(inputClassName, "bolt-textfield-input flex-grow", autoAdjustHeight && "bolt-textfield-auto-adjust", resizable && "bolt-textfield-auto-unresizable", prefixIconProps && "bolt-textfield-input-with-prefix", suffixIconProps && "bolt-textfield-input-with-suffix", activatable && "activatable"); var style = maxWidth !== undefined ? { maxWidth: maxWidth } : {}; var element = (React.createElement(TagName, __assign({}, tagSpecificProps, { "aria-activedescendant": getSafeId(ariaActiveDescendant), "aria-autocomplete": ariaAutoComplete, "aria-controls": getSafeId(ariaControls), "aria-describedby": getSafeId(ariaDescribedBy), "aria-disabled": disabled, "aria-expanded": ariaExpanded, "aria-haspopup": ariaHasPopup, "aria-invalid": ariaInvalid, "aria-label": ariaLabel === undefined && placeholder ? placeholder : ariaLabel, "aria-labelledby": getSafeId(ariaLabelledBy) || getSafeId(formItemContext.ariaLabelledById), "aria-readonly": inputType && inputType !== "text" ? readOnly : undefined, "aria-roledescription": ariaRoleDescription, autoFocus: autoFocus, "data-focuszone": !disabled && !excludeFocusZone ? zoneContext.focuszoneId : undefined, disabled: disabled, className: className, id: getSafeId(inputId), maxLength: maxLength, onBlur: focusStatus.onBlur, onClick: onClick, onChange: function (e) { _this.props.onChange && _this.props.onChange(e, e.target.value); // Adjust height synchronously. If we wait until the React update effect, then // the text area has already been painted in a partially-scrolled state which // causes some ugly flickering. _this.adjustHeight(); }, onFocus: function (event) { if (autoSelect && inputElement.current) { inputElement.current.select(); } focusStatus.onFocus && focusStatus.onFocus(event); }, onKeyDown: onKeyDown, onKeyPress: onKeyPress, onKeyUp: onKeyUp, onPaste: onPaste, placeholder: placeholder, readOnly: readOnly, required: required, ref: inputElement, role: role, style: style, spellCheck: spellCheck, tabIndex: getTabIndex(this.props), value: value || "" }))); // We will use a hidden element behind the input to measure the height. // This prevents the page from performing re-layout when measuring. if (multiline && autoAdjustHeight) { element = (React.createElement("div", { className: "flex-row flex-grow relative" }, React.createElement(TagName, { "aria-hidden": true, className: css("bolt-textfield-auto-adjust-hidden", className), ref: this.hiddenElement, role: "presentation" }), element)); } return (React.createElement(React.Fragment, null, prefixIconProps && Icon(__assign(__assign({ size: IconSize.medium }, prefixIconProps), { className: css(prefixIconProps.className, "prefix", !prefixIconProps.render && "bolt-textfield-icon", ((placeholder && !value) || prefixIconProps.render) && "bolt-textfield-no-text"), onClick: function (e) { prefixIconProps && prefixIconProps.onClick && prefixIconProps.onClick(e); focus(); } })), tooltipProps ? React.createElement(Tooltip, __assign({}, tooltipProps), element) : element, suffixIconProps && Icon(__assign(__assign({ size: IconSize.medium }, suffixIconProps), { className: css(suffixIconProps.className, "suffix", !suffixIconProps.render && "bolt-textfield-icon", ((placeholder && !value) || suffixIconProps.render) && "bolt-textfield-no-text", suffixIconProps.onClick && "cursor-pointer"), onClick: function (e) { suffixIconProps && suffixIconProps.onClick && suffixIconProps.onClick(e); focus(); } })))); }; TextFieldInnerValue.prototype.componentDidMount = function () { this.adjustHeight(); }; TextFieldInnerValue.prototype.componentDidUpdate = function () { this.adjustHeight(); }; TextFieldInnerValue.prototype.adjustHeight = function () { var hiddenElement = this.hiddenElement; var _a = this.props, autoAdjustHeight = _a.autoAdjustHeight, inputElement = _a.inputElement, multiline = _a.multiline, value = _a.value; if (!autoAdjustHeight) { this.adjustedHeightValue = ""; this.adjustedHeight = -1; return; } // If this is a multi-line, auto-adjust text area, adjust the height based on the current content if (multiline && inputElement.current && hiddenElement.current && value !== this.adjustedHeightValue) { hiddenElement.current.value = inputElement.current.value; if (this.adjustedHeight !== hiddenElement.current.scrollHeight) { this.adjustedHeight = hiddenElement.current.scrollHeight; this.adjustedHeightValue = inputElement.current.value; inputElement.current.style.height = this.adjustedHeight + "px"; } } }; return TextFieldInnerValue; }(React.Component));