import React, { Component } from 'react';
import InfoIcon from '../InfoIcon';
import uniqueId from 'lodash/uniqueId';
import Text, { SIZES, SKINS, WEIGHTS } from '../Text';
import { ALIGN, DATA_HOOKS, PLACEMENT, STATUS } from './FormField.constants';
import { st, classes } from './FormField.st.css.js';
import { StatusAlertFilledSmall, StatusWarningFilledSmall, } from '@wix/wix-ui-icons-common';
import { Asterisk } from '@wix/wix-ui-icons-common/system';
import { StatusContext } from './StatusContext';
import { FieldSetContext } from '../FieldSet/FieldSet.context';
import { IconThemeContext } from '../WixDesignSystemIconThemeProvider/IconThemeContext';
export class FormField extends Component {
    constructor(props) {
        super(props);
        this.state = {
            lengthLeft: undefined,
        };
        this.childrenRenderPropInterface = {
            setCharactersLeft: (lengthLeft) => this.setState({ lengthLeft }),
        };
        this._hasCharCounter = () => this.props.charCount !== undefined ||
            typeof this.state.lengthLeft === 'number';
        this.charactersLeft = (lengthLeft) => {
            const { labelSize } = this.props;
            const colorProps = lengthLeft && lengthLeft >= 0
                ? { light: true, secondary: true }
                : { skin: SKINS.error };
            return (React.createElement(Text, { className: st(classes.charCount, { labelSize }), size: SIZES.small, weight: WEIGHTS.normal, ...colorProps, dataHook: DATA_HOOKS.counter, children: lengthLeft }));
        };
        this._renderCharCounter = () => {
            if (!this._hasCharCounter()) {
                return;
            }
            const { charCount } = this.props;
            return this.charactersLeft(charCount !== undefined ? charCount : this.state.lengthLeft);
        };
        this._renderInfoIcon = () => {
            const { infoContent, infoTooltipProps, showInfoIconOnHover } = this.props;
            return (infoContent && (React.createElement(InfoIcon, { dataHook: DATA_HOOKS.infoIcon, className: st(classes.infoIcon, {
                    showInfoIconOnHover: String(showInfoIconOnHover),
                }), content: infoContent, tooltipProps: infoTooltipProps, size: "small" })));
        };
        this._renderSuffix = () => {
            const { suffix } = this.props;
            return ((suffix || this._hasCharCounter()) && (React.createElement("div", { "data-hook": DATA_HOOKS.suffix, className: st(classes.suffix, {
                    noLabel: !this.props.label || this.props.labelPlacement !== PLACEMENT.top,
                }) }, suffix ? suffix : this._renderCharCounter())));
        };
        this._hasInlineElements = (label, labelPlacement) => {
            const hasInlineLabel = label &&
                (labelPlacement === PLACEMENT.left || labelPlacement === PLACEMENT.right);
            const hasInlineIndicator = !label && (this.props.required || !!this.props.infoContent);
            return hasInlineLabel || hasInlineIndicator;
        };
        this._renderLabel = ({ trimLongText, labelSize, asterisk, }) => {
            const { label, id, required, infoContent, ellipsis, maxLines } = this.props;
            const weight = labelSize === 'tiny' ? 'normal' : undefined;
            const hasSuffix = required || infoContent;
            return (React.createElement(Text, { size: labelSize, weight: weight, htmlFor: id, id: this.labelId, tagName: "label", dataHook: DATA_HOOKS.label, ellipsis: ellipsis ?? trimLongText, maxLines: maxLines, style: {
                    display: 'block', // allows the label to be centered vertically
                }, secondary: true, className: st(classes.label, {
                    labelSize,
                    size: labelSize,
                }), suffix: hasSuffix ? (React.createElement(React.Fragment, null,
                    required && asterisk,
                    this._renderInfoIcon())) : undefined }, label));
        };
        this._renderStatusIcon = (icons) => {
            const { status } = this.props;
            if (!status || status === 'loading')
                return;
            const iconByStatus = {
                [STATUS.error]: icons.StatusAlertFilledSmall,
                [STATUS.warning]: icons.StatusWarningFilledSmall,
            };
            const Icon = iconByStatus[status];
            return (React.createElement("div", { className: classes.statusIcon },
                React.createElement(Icon, null)));
        };
        this._renderStatusMessage = (icons) => {
            const { statusMessage, status, labelSize } = this.props;
            return (React.createElement("div", { className: st(classes.statusMessage, {
                    status,
                    labelSize,
                }) },
                (status === STATUS.error || status === STATUS.warning) &&
                    this._renderStatusIcon(icons),
                React.createElement(Text, { id: this.statusId, dataHook: DATA_HOOKS.statusMessage, skin: status === STATUS.error ? 'error' : 'standard', secondary: status !== STATUS.error, size: "tiny" }, statusMessage)));
        };
        this._getCustomColumns = () => {
            const { labelPlacement, labelWidth, inputWidth } = this.props;
            const labelColumn = labelWidth ?? 'auto';
            const inputColumn = inputWidth ?? 'auto';
            if (labelPlacement === PLACEMENT.left) {
                return `${labelColumn} ${inputColumn}`;
            }
            else if (labelPlacement === PLACEMENT.right) {
                return `${inputColumn} ${labelColumn}`;
            }
            else
                return undefined;
        };
        this.labelId = props.labelId || uniqueId('formfield-');
        this.statusId = props.labelId
            ? `${props.labelId}-status`
            : uniqueId('formfield-status-');
    }
    _renderChildren() {
        const { children } = this.props;
        if (typeof children === 'function') {
            return children(this.childrenRenderPropInterface);
        }
        return children;
    }
    render() {
        const { label, labelPlacement, labelAlignment, labelSize, required, dataHook, children, classNames, stretchContent, statusMessage, status, labelWidth, inputWidth, ellipsis, } = this.props;
        const rootStyles = label
            ? {
                labelPlacement,
                labelAlignment,
                stretchContent,
                required,
                minLabelHeight: !children,
            }
            : {
                stretchContent,
                required,
                minLabelHeight: !children,
            };
        const hasInlineElements = this._hasInlineElements(label, labelPlacement);
        const hasCustomWidth = !!labelWidth || !!inputWidth;
        return (React.createElement(IconThemeContext.Consumer, null, ({ icons: themeIcons = {} }) => {
            const icons = {
                Asterisk: themeIcons.FormField?.Asterisk || Asterisk,
                StatusAlertFilledSmall: themeIcons.FormField?.StatusAlertFilledSmall ||
                    StatusAlertFilledSmall,
                StatusWarningFilledSmall: themeIcons.FormField?.StatusWarningFilledSmall ||
                    StatusWarningFilledSmall,
            };
            const asterisk = (React.createElement("div", { "data-hook": DATA_HOOKS.asterisk, className: classes.asterisk },
                React.createElement(icons.Asterisk, null)));
            return (React.createElement("div", { ...(this.props.showInfoIconOnHover && {
                    'data-hoverable-action-trigger': true,
                }), "data-hook": dataHook, "data-status": status, className: st(classes.root, {
                    ...rootStyles,
                    ...(label ? { labelSize } : {}),
                    hasInlineElements,
                }, classNames), style: labelPlacement !== PLACEMENT.top && hasCustomWidth
                    ? { gridTemplateColumns: this._getCustomColumns() }
                    : {} },
                label && labelPlacement === PLACEMENT.top && (React.createElement("div", { className: classes.labelRow },
                    React.createElement("div", { className: classes.labelRowMain }, this._renderLabel({
                        trimLongText: true,
                        labelSize,
                        asterisk,
                    })),
                    this._renderSuffix())),
                children && (React.createElement("div", { "data-hook": DATA_HOOKS.children, className: st(classes.children, {
                        childrenWithInlineLabel: hasInlineElements,
                    }) },
                    !label && this._renderSuffix(),
                    React.createElement(FieldSetContext.Consumer, null, fieldSet => (React.createElement(StatusContext.Provider, { value: {
                            status,
                            ariaLabelledBy: this.labelId,
                            ariaDescribedBy: [
                                this.statusId,
                                status === fieldSet.status && fieldSet.statusId,
                            ]
                                .filter(Boolean)
                                .join(' '),
                        } }, this._renderChildren()))))),
                hasInlineElements && (React.createElement("div", { className: st(classes.labelRow, {
                        ellipsis,
                    }) },
                    React.createElement("div", { className: classes.labelRowMain }, this._renderLabel({
                        trimLongText: false,
                        labelSize,
                        asterisk,
                    })),
                    !!label && this._renderSuffix())),
                statusMessage && this._renderStatusMessage(icons)));
        }));
    }
}
FormField.displayName = 'FormField';
FormField.defaultProps = {
    required: false,
    stretchContent: true,
    labelSize: 'small',
    labelPlacement: PLACEMENT.top,
    labelAlignment: ALIGN.middle,
};
export default FormField;
//# sourceMappingURL=FormField.js.map