<script setup>
import { computed, ref, watch, nextTick, useSlots, onMounted } from "vue";
import { useNamespace, useFormItem, useLocale, useConfig } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { calcTextareaHeight } from "./utils";
defineOptions({
  name: "YhInput"
});
const props = defineProps({
  modelValue: { type: [String, Number], required: false },
  type: { type: null, required: false, default: "text" },
  size: { type: null, required: false, default: void 0 },
  variant: { type: null, required: false, default: "default" },
  status: { type: null, required: false, default: "" },
  loading: { type: Boolean, required: false, default: false },
  placeholder: { type: String, required: false },
  disabled: { type: Boolean, required: false, default: false },
  readonly: { type: Boolean, required: false, default: false },
  clearable: { type: Boolean, required: false, default: false },
  clearOnEscape: { type: Boolean, required: false, default: false },
  selectOnFocus: { type: Boolean, required: false, default: false },
  showPassword: { type: Boolean, required: false, default: false },
  showWordLimit: { type: Boolean, required: false, default: false },
  countConfig: { type: Object, required: false },
  maxlength: { type: [Number, String], required: false },
  minlength: { type: [Number, String], required: false },
  prefixIcon: { type: null, required: false },
  suffixIcon: { type: null, required: false },
  clearIcon: { type: null, required: false },
  prefix: { type: String, required: false },
  suffix: { type: String, required: false },
  list: { type: String, required: false },
  autofocus: { type: Boolean, required: false, default: false },
  autocomplete: { type: String, required: false, default: "off" },
  name: { type: String, required: false },
  form: { type: String, required: false },
  id: { type: String, required: false },
  tabindex: { type: [String, Number], required: false },
  ariaLabel: { type: String, required: false, default: void 0 },
  label: { type: String, required: false, default: void 0 },
  inputmode: { type: String, required: false, default: void 0 },
  modelModifiers: { type: Object, required: false, default: () => ({}) },
  validateEvent: { type: Boolean, required: false, default: true },
  inputStyle: { type: [String, Object], required: false },
  formatter: { type: Function, required: false },
  parser: { type: Function, required: false },
  rows: { type: Number, required: false, default: 2 },
  autosize: { type: [Boolean, Object], required: false },
  resize: { type: String, required: false },
  themeOverrides: { type: null, required: false }
});
const emit = defineEmits(["update:modelValue", "input", "change", "focus", "blur", "clear", "keydown", "keyup", "compositionstart", "compositionupdate", "compositionend"]);
const slots = useSlots();
const ns = useNamespace("input");
const { t } = useLocale();
const inputRef = ref();
const textareaRef = ref();
const wrapperRef = ref();
const { form, formItem, validate: triggerValidate } = useFormItem();
const { themeStyle } = useComponentTheme(
  "input",
  computed(() => props.themeOverrides)
);
const { globalSize } = useConfig();
const inputSize = computed(
  () => props.size || formItem?.size || form?.size || globalSize.value || "default"
);
const focused = ref(false);
const hovering = ref(false);
const isComposing = ref(false);
const passwordVisible = ref(false);
const textareaCalcStyle = ref({});
const inputOrTextarea = computed(() => inputRef.value || textareaRef.value);
const isTextarea = computed(() => props.type === "textarea");
const nativeInputValue = computed(() => {
  const value = props.modelValue === null || props.modelValue === void 0 ? "" : String(props.modelValue);
  if (props.formatter && !isTextarea.value) {
    return props.formatter(value);
  }
  return value;
});
const showClear = computed(
  () => props.clearable && !props.disabled && !props.readonly && !!nativeInputValue.value && (focused.value || hovering.value)
);
const showPasswordIcon = computed(
  () => props.showPassword && !props.disabled && !props.readonly && !!nativeInputValue.value
);
const textLength = computed(() => {
  const value = props.modelValue === null || props.modelValue === void 0 ? "" : String(props.modelValue);
  if (props.countConfig?.calculate) {
    return props.countConfig.calculate(value);
  }
  return value.length;
});
const showWordLimitCount = computed(
  () => props.showWordLimit && !!props.maxlength && (props.type === "text" || props.type === "textarea") && !props.disabled && !props.readonly
);
const inputExceed = computed(
  () => showWordLimitCount.value && textLength.value > Number(props.maxlength)
);
const isLoading = computed(() => props.loading && !props.disabled);
const hasPrepend = computed(() => !!slots.prepend);
const hasAppend = computed(() => !!slots.append);
const hasPrefix = computed(() => !!slots.prefix || !!props.prefixIcon || !!props.prefix);
const hasSuffix = computed(
  () => !!slots.suffix || !!props.suffixIcon || !!props.suffix || showClear.value || showPasswordIcon.value || isLoading.value
);
const mergedStatus = computed(() => {
  if (props.status) return props.status;
  if (formItem?.validateStatus === "error") return "error";
  if (formItem?.validateStatus === "success") return "success";
  return "";
});
const wrapperClasses = computed(() => [
  ns.b(),
  ns.m(inputSize.value),
  ns.is("disabled", props.disabled),
  ns.is("focused", focused.value),
  ns.is("textarea", isTextarea.value),
  ns.is("exceed", inputExceed.value),
  ns.is("loading", isLoading.value),
  // Feature 1: Variant
  props.variant && props.variant !== "default" ? ns.m(`variant-${props.variant}`) : "",
  // Feature 3: Status
  mergedStatus.value ? ns.m(`status-${mergedStatus.value}`) : "",
  {
    [ns.b("group")]: hasPrepend.value || hasAppend.value,
    [ns.is("prepend")]: hasPrepend.value,
    [ns.is("append")]: hasAppend.value
  }
]);
const wrapperStyle = computed(() => ({
  ...themeStyle.value
}));
const inputClasses = computed(() => [ns.e("inner"), ns.is("disabled", props.disabled)]);
const textareaStyle = computed(() => {
  return [props.inputStyle, textareaCalcStyle.value, { resize: props.resize }];
});
const setNativeInputValue = () => {
  const input = inputOrTextarea.value;
  if (!input || input.value === nativeInputValue.value) return;
  input.value = nativeInputValue.value;
};
const handleInput = (event) => {
  const target = event.target;
  let value = target.value;
  if (isComposing.value) return;
  if (props.parser) {
    value = props.parser(value);
  }
  if (props.modelModifiers?.trim) {
    value = value.trim();
  }
  if (props.modelModifiers?.number) {
    const n = parseFloat(value);
    emit("update:modelValue", isNaN(n) ? value : n);
    emit("input", isNaN(n) ? value : n);
  } else {
    emit("update:modelValue", value);
    emit("input", value);
  }
};
const handleChange = (event) => {
  const target = event.target;
  emit("change", target.value);
  if (props.validateEvent) {
    nextTick(() => {
      triggerValidate("change");
    });
  }
};
const handleFocus = (event) => {
  focused.value = true;
  emit("focus", event);
  if (props.selectOnFocus) {
    nextTick(() => {
      inputOrTextarea.value?.select();
    });
  }
};
const handleBlur = (event) => {
  focused.value = false;
  emit("blur", event);
  if (props.validateEvent) {
    nextTick(() => {
      triggerValidate("blur");
    });
  }
};
const handleMouseEnter = () => {
  hovering.value = true;
};
const handleMouseLeave = () => {
  hovering.value = false;
};
const handleClear = () => {
  emit("update:modelValue", "");
  emit("change", "");
  emit("clear");
  emit("input", "");
  const input = inputOrTextarea.value;
  if (input) {
    input.value = "";
  }
  nextTick(() => {
    focus();
  });
};
const handleKeydown = (event) => {
  if (props.clearOnEscape && event.key === "Escape" && !props.disabled && !props.readonly) {
    handleClear();
  }
  emit("keydown", event);
};
const handleKeyup = (event) => {
  emit("keyup", event);
};
const handlePasswordToggle = () => {
  passwordVisible.value = !passwordVisible.value;
  nextTick(() => {
    focus();
  });
};
const handleCompositionStart = (event) => {
  isComposing.value = true;
  emit("compositionstart", event);
};
const handleCompositionUpdate = (event) => {
  emit("compositionupdate", event);
};
const handleCompositionEnd = (event) => {
  if (isComposing.value) {
    isComposing.value = false;
    handleInput(event);
  }
  emit("compositionend", event);
};
const focus = () => {
  inputOrTextarea.value?.focus();
};
const blur = () => {
  inputOrTextarea.value?.blur();
};
const select = () => {
  inputOrTextarea.value?.select();
};
const clear = () => {
  handleClear();
};
const resizeTextarea = () => {
  const { type, autosize } = props;
  if (type !== "textarea") return;
  if (!autosize) {
    textareaCalcStyle.value = {};
    return;
  }
  const minRows = typeof autosize === "object" ? autosize.minRows : void 0;
  const maxRows = typeof autosize === "object" ? autosize.maxRows : void 0;
  const textarea = textareaRef.value;
  if (!textarea) return;
  const style = calcTextareaHeight(textarea, minRows, maxRows);
  textareaCalcStyle.value = {
    height: style.height,
    minHeight: style.minHeight
  };
};
watch(
  () => props.modelValue,
  () => {
    nextTick(() => {
      setNativeInputValue();
      resizeTextarea();
    });
  }
);
onMounted(() => {
  setNativeInputValue();
  resizeTextarea();
  if (props.autofocus) {
    focus();
  }
});
defineExpose({
  ref: inputOrTextarea.value,
  wrapperRef: wrapperRef.value,
  focus,
  blur,
  select,
  clear,
  get textLength() {
    return textLength.value;
  }
});
</script>

<template>
  <div
    ref="wrapperRef"
    :class="wrapperClasses"
    :style="wrapperStyle"
    @mouseenter="handleMouseEnter"
    @mouseleave="handleMouseLeave"
  >
    <!-- 前置元素 -->
    <div v-if="hasPrepend" :class="ns.e('prepend')">
      <slot name="prepend" />
    </div>

    <!-- 输入框包装器 -->
    <div :class="ns.e('wrapper')">
      <!-- 前置图标/文本/内容 -->
      <span v-if="hasPrefix" :class="ns.e('prefix')">
        <slot name="prefix">
          <!-- Feature 6: prefix string prop -->
          <span v-if="prefix" :class="ns.e('prefix-text')">{{ prefix }}</span>
          <component
            v-else-if="prefixIcon && typeof prefixIcon !== 'string'"
            :is="prefixIcon"
            :class="ns.e('icon')"
          />
          <span v-else-if="prefixIcon" :class="ns.e('icon')">{{ prefixIcon }}</span>
        </slot>
      </span>

      <!-- 文本域 -->
      <textarea
        v-if="isTextarea"
        ref="textareaRef"
        :class="inputClasses"
        :value="nativeInputValue"
        :placeholder="placeholder ?? t('input.placeholder')"
        :disabled="disabled"
        :readonly="readonly"
        :maxlength="maxlength"
        :minlength="minlength"
        :rows="rows"
        :name="name"
        :id="id"
        :tabindex="tabindex"
        :autocomplete="autocomplete"
        :autofocus="autofocus"
        :aria-label="ariaLabel || label || (placeholder ?? t('input.placeholder'))"
        :inputmode="inputmode"
        :style="textareaStyle"
        @input="handleInput"
        @change="handleChange"
        @focus="handleFocus"
        @blur="handleBlur"
        @keydown="handleKeydown"
        @keyup="handleKeyup"
        @compositionstart="handleCompositionStart"
        @compositionupdate="handleCompositionUpdate"
        @compositionend="handleCompositionEnd"
      />

      <!-- 普通输入框 -->
      <input
        v-else
        ref="inputRef"
        :class="inputClasses"
        :type="showPassword ? passwordVisible ? 'text' : 'password' : type"
        :value="nativeInputValue"
        :placeholder="placeholder ?? t('input.placeholder')"
        :disabled="disabled"
        :readonly="readonly"
        :maxlength="maxlength"
        :minlength="minlength"
        :name="name"
        :id="id"
        :tabindex="tabindex"
        :list="list"
        :autocomplete="autocomplete"
        :autofocus="autofocus"
        :style="inputStyle"
        :aria-label="ariaLabel || label || (placeholder ?? t('input.placeholder'))"
        :inputmode="inputmode"
        :aria-invalid="mergedStatus === 'error'"
        :aria-describedby="mergedStatus === 'error' ? formItem?.errorId : void 0"
        @input="handleInput"
        @change="handleChange"
        @focus="handleFocus"
        @blur="handleBlur"
        @keydown="handleKeydown"
        @keyup="handleKeyup"
        @compositionstart="handleCompositionStart"
        @compositionupdate="handleCompositionUpdate"
        @compositionend="handleCompositionEnd"
      />

      <!-- 后置图标/文本/内容 -->
      <span v-if="hasSuffix" :class="ns.e('suffix')">
        <!-- Feature 2: 加载状态图标 -->
        <span v-if="isLoading" :class="[ns.e('icon'), ns.e('loading')]">
          <slot name="loadingIcon">
            <svg
              viewBox="0 0 1024 1024"
              xmlns="http://www.w3.org/2000/svg"
              width="1em"
              height="1em"
              class="yh-input__loading-spin"
            >
              <path
                fill="currentColor"
                d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
              />
            </svg>
          </slot>
        </span>

        <!-- 清空按钮 -->
        <span
          v-if="showClear && !isLoading"
          :class="[ns.e('icon'), ns.e('clear')]"
          @mousedown.prevent
          @click.stop="handleClear"
        >
          <slot name="clearIcon">
            <svg
              viewBox="0 0 1024 1024"
              xmlns="http://www.w3.org/2000/svg"
              width="1em"
              height="1em"
            >
              <path
                fill="currentColor"
                d="m466.752 512-90.496-90.496a32 32 0 0 1 45.248-45.248L512 466.752l90.496-90.496a32 32 0 1 1 45.248 45.248L557.248 512l90.496 90.496a32 32 0 1 1-45.248 45.248L512 557.248l-90.496 90.496a32 32 0 0 1-45.248-45.248L466.752 512zM512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm0 832a384 384 0 1 0 0-768 384 384 0 0 0 0 768z"
              />
            </svg>
          </slot>
        </span>

        <!-- 密码切换按钮 -->
        <span
          v-if="showPasswordIcon"
          :class="[ns.e('icon'), ns.e('password')]"
          @click.stop="handlePasswordToggle"
        >
          <svg
            v-if="passwordVisible"
            viewBox="0 0 24 24"
            width="1em"
            height="1em"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            style="overflow: visible"
          >
            <path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z" />
            <circle cx="12" cy="12" r="3" />
          </svg>
          <svg
            v-else
            viewBox="0 0 24 24"
            width="1em"
            height="1em"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            style="overflow: visible"
          >
            <path
              d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"
            />
            <line x1="3" y1="3" x2="21" y2="21" />
          </svg>
        </span>

        <!-- 后置图标/文本插槽 -->
        <slot name="suffix">
          <!-- Feature 6: suffix string prop -->
          <span v-if="suffix" :class="ns.e('suffix-text')">{{ suffix }}</span>
          <component
            v-else-if="suffixIcon && typeof suffixIcon !== 'string'"
            :is="suffixIcon"
            :class="ns.e('icon')"
          />
          <span v-else-if="suffixIcon" :class="ns.e('icon')">{{ suffixIcon }}</span>
        </slot>
      </span>

      <!-- 字数统计 (输入框内部，仅针对 type=text) -->
      <span v-if="showWordLimitCount && !isTextarea" :class="ns.e('count')">
        {{ textLength }} / {{ maxlength }}
      </span>
    </div>

    <!-- 后置元素 -->
    <div v-if="hasAppend" :class="ns.e('append')">
      <slot name="append" />
    </div>

    <!-- 字数统计 (Textarea 外部右下角) -->
    <span
      v-if="showWordLimitCount && isTextarea"
      :class="[ns.e('count'), ns.em('count', 'textarea')]"
    >
      {{ textLength }} / {{ maxlength }}
    </span>
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
@keyframes yh-input-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
.yh-input {
  --yh-input-height: var(--yh-component-size-default);
  --yh-input-font-size: var(--yh-font-size-base);
  --yh-input-padding: 0 var(--yh-spacing-md);
  --yh-input-border-color: var(--yh-border-color);
  --yh-input-hover-border-color: var(--yh-input-focus-border-color);
  --yh-input-focus-border-color: var(--yh-color-primary);
  --yh-input-bg-color: var(--yh-fill-color-blank);
  position: relative;
  display: inline-flex;
  width: 100%;
  vertical-align: middle;
  box-sizing: border-box;
  font-size: var(--yh-input-font-size);
}
.yh-input__wrapper {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-grow: 1;
  width: 100%;
  min-width: 0;
  padding: var(--yh-input-padding);
  background-color: var(--yh-input-bg-color);
  border: 1px solid var(--yh-input-border-color);
  border-radius: var(--yh-radius-base);
  transition: var(--yh-transition-base);
  box-sizing: border-box;
  position: relative;
}
.yh-input__wrapper:hover {
  border-color: var(--yh-input-hover-border-color);
}

.yh-input.is-focused .yh-input__wrapper {
  border-color: var(--yh-input-focus-border-color);
  box-shadow: 0 0 0 2px var(--yh-color-primary-light-8);
  z-index: 2;
}

.yh-input.is-disabled .yh-input__wrapper {
  background-color: var(--yh-fill-color-light);
  border-color: var(--yh-border-color-light);
  cursor: not-allowed;
}

.yh-input.is-disabled .yh-input__inner {
  color: var(--yh-text-color-disabled);
  cursor: not-allowed;
}

.yh-input--variant-filled .yh-input__wrapper {
  background-color: var(--yh-fill-color-light);
  border-color: transparent;
}
.yh-input--variant-filled .yh-input__wrapper:hover {
  background-color: var(--yh-fill-color);
  border-color: transparent;
}

.yh-input--variant-filled.is-focused .yh-input__wrapper {
  background-color: var(--yh-fill-color-blank);
  border-color: var(--yh-input-focus-border-color);
  box-shadow: 0 0 0 2px var(--yh-color-primary-light-8);
}

.yh-input--variant-borderless .yh-input__wrapper {
  border-color: transparent !important;
  box-shadow: none !important;
  background-color: transparent;
  padding-left: 0;
  padding-right: 0;
}

.yh-input--variant-underlined .yh-input__wrapper {
  border-top-color: transparent;
  border-left-color: transparent;
  border-right-color: transparent;
  border-radius: 0;
  background-color: transparent;
  padding-left: 0;
  padding-right: 0;
}
.yh-input--variant-underlined .yh-input__wrapper:hover {
  border-bottom-color: var(--yh-input-hover-border-color);
  border-top-color: transparent;
  border-left-color: transparent;
  border-right-color: transparent;
}

.yh-input--variant-underlined.is-focused .yh-input__wrapper {
  border-bottom-color: var(--yh-input-focus-border-color);
  border-top-color: transparent;
  border-left-color: transparent;
  border-right-color: transparent;
  box-shadow: 0 2px 0 0 var(--yh-color-primary-light-8);
}

.yh-input--status-success > .yh-input__wrapper, .yh-input--status-success > .yh-input__wrapper:hover {
  border-color: var(--yh-color-success) !important;
}
.yh-input--status-success.is-focused > .yh-input__wrapper {
  box-shadow: 0 0 0 2px rgba(103, 194, 58, 0.2);
}

.yh-input--status-warning > .yh-input__wrapper, .yh-input--status-warning > .yh-input__wrapper:hover {
  border-color: var(--yh-color-warning) !important;
}
.yh-input--status-warning.is-focused > .yh-input__wrapper {
  box-shadow: 0 0 0 2px rgba(230, 162, 60, 0.2);
}

.yh-input--status-error > .yh-input__wrapper, .yh-input--status-error > .yh-input__wrapper:hover {
  border-color: var(--yh-color-danger) !important;
}
.yh-input--status-error.is-focused > .yh-input__wrapper {
  box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.2);
}

.yh-input.is-loading {
  cursor: wait;
}
.yh-input.is-loading .yh-input__inner {
  cursor: wait;
}

.yh-input__loading {
  color: var(--yh-text-color-placeholder);
  font-size: 16px;
  display: inline-flex;
  align-items: center;
}
.yh-input__loading .yh-input__loading-spin {
  animation: yh-input-spin 1s linear infinite;
}

.yh-input__prefix-text {
  color: var(--yh-text-color-secondary);
  font-size: inherit;
  white-space: nowrap;
  margin-right: 4px;
  user-select: none;
  pointer-events: none;
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.yh-input__suffix-text {
  color: var(--yh-text-color-secondary);
  font-size: inherit;
  white-space: nowrap;
  margin-left: 4px;
  user-select: none;
  pointer-events: none;
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.yh-input__inner {
  flex: 1;
  width: 100%;
  min-width: 0;
  height: calc(var(--yh-input-height) - 2px);
  line-height: calc(var(--yh-input-height) - 2px);
  color: var(--yh-text-color-regular);
  font-size: inherit;
  background: none;
  border: none;
  outline: none;
  padding: 0;
  box-sizing: border-box;
  appearance: none;
}
.yh-input__inner::placeholder {
  color: var(--yh-text-color-placeholder);
}
.yh-input__inner:-webkit-autofill, .yh-input__inner:autofill {
  transition: background-color 50000s ease-in-out 0s, color 50000s ease-in-out 0s;
  -webkit-text-fill-color: var(--yh-text-color-regular) !important;
}

.yh-input.is-textarea {
  flex-direction: column;
  align-items: stretch;
  display: inline-flex;
  vertical-align: bottom;
}
.yh-input.is-textarea .yh-input__wrapper {
  padding: 0;
  border: none;
  box-shadow: none;
  background-color: transparent;
}
.yh-input.is-textarea .yh-input__inner {
  border: 1px solid var(--yh-input-border-color);
  border-radius: var(--yh-radius-base);
  transition: var(--yh-transition-base);
  padding: 8px 12px;
  line-height: 1.5;
  height: auto;
  min-height: 32px;
  width: 100%;
  box-sizing: border-box;
}
.yh-input.is-textarea .yh-input__inner:hover {
  border-color: var(--yh-input-hover-border-color);
}
.yh-input.is-textarea.is-focused .yh-input__inner {
  border-color: var(--yh-input-focus-border-color);
  box-shadow: 0 0 0 2px var(--yh-color-primary-light-8);
}
.yh-input.is-textarea.yh-input--status-success .yh-input__inner {
  border-color: var(--yh-color-success) !important;
}
.yh-input.is-textarea.yh-input--status-warning .yh-input__inner {
  border-color: var(--yh-color-warning) !important;
}
.yh-input.is-textarea.yh-input--status-error .yh-input__inner {
  border-color: var(--yh-color-danger) !important;
}
.yh-input__suffix {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 100%;
  margin-left: 8px;
  flex-shrink: 0;
}

.yh-input__prefix {
  display: inline-flex;
  align-items: center;
  height: 100%;
  margin-right: 8px;
  flex-shrink: 0;
}

.yh-input__icon {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color var(--yh-duration-base);
  color: var(--yh-text-color-placeholder);
  font-size: 16px;
  line-height: 1;
  flex-shrink: 0;
}
.yh-input__icon.yh-input__clear, .yh-input__icon.yh-input__password {
  cursor: pointer;
}
.yh-input__icon.yh-input__clear:hover, .yh-input__icon.yh-input__password:hover {
  color: var(--yh-text-color-regular);
}

.yh-input__count {
  display: inline-flex;
  align-items: center;
  color: var(--yh-text-color-placeholder);
  font-size: 12px;
  margin-left: 8px;
  white-space: nowrap;
  user-select: none;
  pointer-events: none;
}
.yh-input__count--textarea {
  display: block;
  text-align: right;
  margin-top: 4px;
  margin-left: 0;
  padding: 0;
  line-height: 1;
  background: transparent;
}

.yh-input--large {
  --yh-input-height: var(--yh-component-size-large);
}

.yh-input--small {
  --yh-input-height: var(--yh-component-size-small);
  font-size: var(--yh-font-size-xs);
}

.yh-input.yh-input-group {
  display: inline-flex;
  align-items: stretch;
}
.yh-input.yh-input-group > .yh-input__prepend,
.yh-input.yh-input-group > .yh-input__append {
  padding: 0 16px;
  white-space: nowrap;
  background-color: var(--yh-fill-color-light);
  color: var(--yh-text-color-secondary);
  border: 1px solid var(--yh-input-border-color);
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  flex-shrink: 0;
  transition: border-color var(--yh-duration-base);
}
.yh-input.yh-input-group > .yh-input__prepend .yh-button,
.yh-input.yh-input-group > .yh-input__prepend .yh-select,
.yh-input.yh-input-group > .yh-input__append .yh-button,
.yh-input.yh-input-group > .yh-input__append .yh-select {
  margin: -1px -16px;
  border-radius: 0;
  height: var(--yh-input-height, 32px);
}
.yh-input.yh-input-group > .yh-input__prepend .yh-button > .yh-input__wrapper,
.yh-input.yh-input-group > .yh-input__prepend .yh-button > .yh-select__wrapper,
.yh-input.yh-input-group > .yh-input__prepend .yh-select > .yh-input__wrapper,
.yh-input.yh-input-group > .yh-input__prepend .yh-select > .yh-select__wrapper,
.yh-input.yh-input-group > .yh-input__append .yh-button > .yh-input__wrapper,
.yh-input.yh-input-group > .yh-input__append .yh-button > .yh-select__wrapper,
.yh-input.yh-input-group > .yh-input__append .yh-select > .yh-input__wrapper,
.yh-input.yh-input-group > .yh-input__append .yh-select > .yh-select__wrapper {
  background-color: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  border-radius: 0;
}
.yh-input.yh-input-group > .yh-input__prepend {
  border-right: none;
  border-radius: var(--yh-radius-base) 0 0 var(--yh-radius-base);
}
.yh-input.yh-input-group > .yh-input__append {
  border-left: none;
  border-radius: 0 var(--yh-radius-base) var(--yh-radius-base) 0;
}
.yh-input.yh-input-group > .yh-input__wrapper {
  flex: 1;
  border-radius: 0;
  z-index: 1;
  transition: border-color var(--yh-duration-base), box-shadow var(--yh-duration-base);
}
.yh-input.yh-input-group > .yh-input__wrapper:hover, .yh-input.yh-input-group > .yh-input__wrapper:focus-within {
  z-index: 2;
}
.yh-input.yh-input-group.is-prepend:not(.is-append) > .yh-input__wrapper {
  border-radius: 0 var(--yh-radius-base) var(--yh-radius-base) 0;
}
.yh-input.yh-input-group.is-append:not(.is-prepend) > .yh-input__wrapper {
  border-radius: var(--yh-radius-base) 0 0 var(--yh-radius-base);
}
.yh-input.yh-input-group:hover > .yh-input__prepend,
.yh-input.yh-input-group:hover > .yh-input__append {
  border-color: var(--yh-input-hover-border-color);
}
.yh-input.yh-input-group:hover > .yh-input__wrapper {
  border-color: var(--yh-input-hover-border-color);
}
.yh-input.yh-input-group.is-focused > .yh-input__wrapper {
  z-index: 3;
}
</style>
