UNPKG

@octopusdeploy/design-system-components

Version:
210 lines (209 loc) • 9.34 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Text = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const css_1 = require("@emotion/css"); const TextField_1 = __importDefault(require("@mui/material/TextField")); const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens"); const react_1 = __importDefault(require("react")); const uuid_1 = require("uuid"); /* @deprecated * Deprecated: 15/09/2025 * This component is deprecated. * As part of our effort to improve form usability and accessibility, please migrate to TextField where feasible. * We recognize TextField has different styling; if that prevents an immediate swap, you may continue using this * component until all the new form components are in place. */ class Text extends react_1.default.Component { static defaultProps = { type: "text", autoComplete: "off", autoFocus: false, applyMaxWidth: false, multiline: false, showBorder: false, maxRows: 30, maxLength: undefined, textInputRef: (input) => { /* Do nothing */ }, }; textFieldInput = undefined; genericName; uniqueId; constructor(props) { super(props); this.state = { showExternalError: true, }; this.genericName = props.generateUniqueName ? `input-${(0, uuid_1.v4)()}` : typeof props.label === "string" ? props.label : props.placeholder ? props.placeholder : `input-${(0, uuid_1.v4)()}`; this.uniqueId = `${props.label}-${(0, uuid_1.v4)()}`; } // eslint-disable-next-line react/no-unsafe UNSAFE_componentWillMount() { if (this.props.textInputRef) { this.props.textInputRef(this); } } componentWillUnmount() { if (this.props.textInputRef) { this.props.textInputRef(null); } } // eslint-disable-next-line react/no-unsafe UNSAFE_componentWillReceiveProps(nextProps) { const isNewExternalErrorAvailable = nextProps.error !== this.props.error; if (isNewExternalErrorAvailable) { this.setState({ showExternalError: true }); } } getSelection = () => { const input = this.textFieldInput; return { start: input?.selectionStart ?? null, end: input?.selectionEnd ?? null }; }; setValueAndSelection = (selection, value) => { const input = this.textFieldInput; if (!input) return; input.value = value; input.selectionStart = selection.start; input.selectionEnd = selection.end; this.callValidateAndChange(input.value); }; isFocused() { return this.textFieldInput !== undefined && this.textFieldInput === document.activeElement; } select() { if (this.textFieldInput) { this.textFieldInput.select(); } } focus() { if (this.textFieldInput) { this.textFieldInput.focus(); } } blur() { if (this.textFieldInput) { this.textFieldInput.blur(); } } insertAtCursor(value) { if (!this.textFieldInput) { return; } const input = this.textFieldInput; if (input.selectionStart || input.selectionStart === 0) { const startPos = input.selectionStart; const endPos = input.selectionEnd; if (endPos !== null) { input.value = input.value.substring(0, startPos) + value + input.value.substring(endPos, input.value.length); } input.selectionStart = startPos + value.length; input.selectionEnd = startPos + value.length; } else { input.value += value; } this.callValidateAndChange(input.value); } handleChange = (event) => { event.preventDefault(); event.stopPropagation(); const value = event.currentTarget.value; this.callValidateAndChange(value); }; callValidateAndChange = (value) => { if (this.props.validate) { const result = this.props.validate(value); this.setState({ error: result }); if (this.props.onValidate) { this.props.onValidate(result); } } this.setState({ showExternalError: false }); if (this.props.onChange) { this.props.onChange(value); } }; handleKeyPress = (event) => { if (this.props.onKeyPress) { this.props.onKeyPress(event); } }; handleKeyDown = (event) => { if (this.props.onKeyDown) { this.props.onKeyDown(event); } }; render() { const { id, validate, error, onChange, onValidate, value, label, min, max, name, maxLength, placeholder, hideUnderline, warning, monoSpacedFont, onKeyPress, minRows, multiline, applyMaxWidth, showBorder, textInputRef, inputContainerRef, showValueAsTitleAttribute, autoComplete, type, usePlaceholderAsLabel, accessibleName, customMargins, generateUniqueName, helperText, margin, inputProps, ...otherProps } = this.props; const err = this.state.error || (this.state.showExternalError && error); const errorText = err || warning; const val = value ? value : ""; // Play carefully here. There's some interesting combinations happening with SensitiveInput label/placeholder etc. We have tests around this. const inputLabel = usePlaceholderAsLabel && placeholder && !val ? placeholder : label; const commonStyle = { margin: customMargins ? customMargins : !inputLabel ? "1rem 0" : "0 0 1rem 0", pointerEvents: "auto" }; // This allows us to match the padding/alignment of our other select components (AutoComplete, Select, MultiSelect), so we get consistent alignments. const widthStyle = applyMaxWidth ? { maxWidth: "100%" } : {}; const inputId = id || this.uniqueId; const getHelpText = () => { if (errorText) return errorText; if (helperText) return helperText; return null; }; const typeComplete = type === "password" && autoComplete === "off" ? "new-password" : autoComplete; return ((0, jsx_runtime_1.jsx)("div", { className: (0, css_1.cx)(styles.container, { [styles.border]: showBorder }), children: (0, jsx_runtime_1.jsx)(TextField_1.default, { ref: inputContainerRef, id: inputId, className: (0, css_1.cx)(styles.text, { [styles.noUnderline]: hideUnderline }), inputRef: (textFieldInput) => { this.textFieldInput = textFieldInput; }, variant: "standard", type: type, autoComplete: typeComplete, autoCorrect: autoComplete, placeholder: placeholder, title: showValueAsTitleAttribute ? val : undefined, name: name || this.genericName, value: val, label: inputLabel, onChange: this.handleChange, error: !!errorText, helperText: getHelpText(), FormHelperTextProps: { component: "div" }, inputProps: { min: min, max: max, "aria-label": accessibleName }, InputProps: { ...this.props.inputProps, classes: { ...this.props.inputProps?.classes, input: (0, css_1.cx)(this.props.inputProps?.classes?.input, { [styles.monospacedText]: monoSpacedFont }), }, }, minRows: multiline ? minRows || 3 : minRows, multiline: multiline, onKeyPress: this.handleKeyPress, onKeyDown: this.handleKeyDown, style: { ...widthStyle, ...commonStyle }, margin: margin, ...otherProps }) })); } } exports.Text = Text; const muiInputClasses = { input: "MuiInputBase-input", }; const styles = { container: (0, css_1.css)({ width: "100%", }), border: (0, css_1.css)({ padding: `0 ${design_system_tokens_1.space[8]} 0 ${design_system_tokens_1.space[8]}`, border: `${design_system_tokens_1.borderWidth[1]} solid ${design_system_tokens_1.themeTokens.color.border.primary}`, marginBottom: design_system_tokens_1.space[8], }), text: (0, css_1.css)({ verticalAlign: "baseline !important", width: "100% !important", minWidth: "0 !important", }), monospacedText: (0, css_1.css)({ [`&.${muiInputClasses.input}`]: { font: design_system_tokens_1.text.code.regular.medium, }, }), noUnderline: (0, css_1.css)({ borderBottom: 0, "div::before": { // This isn't great because it relies on the structure of MUI's TextField component, but it's the only way I could find to override this here. borderBottom: 0, "div::before": { // This isn't great because it relies on the structure of MUI's TextField component, but it's the only way I could find to override this here. borderBottom: 0, }, "div::after": { // This isn't great because it relies on the structure of MUI's TextField component, but it's the only way I could find to override this here. borderBottom: 0, }, }, }), };