import { vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, createVNode as _createVNode, mergeProps as _mergeProps, resolveDirective as _resolveDirective, vModelText as _vModelText, Fragment as _Fragment } from "vue";
import "./styles/input.css";
import { Teleport, computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { IN_BROWSER, convertToUnit, filterInputAttrs, getCurrentInstance, getUid, propsFactory, useRender } from "@veno-ui/utils";
import { genericComponent, propIsDefined } from "../../utils";
import { FormControl } from "../form-control";
import { InputControl } from "../input-control";
import { Counter } from "../counter";
import { InputControlEmits, filterInputControlProps, filterInputControlSlots, makeInputControlProps } from "../input-control/input-control";
import { FormControlEmits, filterFormControlSlots } from "../form-control/form-control";
import { useProxiedModel } from "../../composables/proxied-model";
import { Intersect } from "../../directives/intersect";
const dirtyTypes = ["color", "file", "time", "date", "datetime-local", "week", "month"];
const makeInputProps = propsFactory({
  /**
   * @zh 自动聚焦
   */
  autofocus: Boolean,
  /**
   * @zh 自动调整大小
   */
  autoResize: Boolean,
  /**
   * @zh 计数器
   */
  counter: [Boolean, Number, String],
  /**
   * @zh 计数器值
   */
  counterValue: Function,
  /**
   * @zh ID
   */
  id: String,
  /**
   * @zh 输入框需要传送到那个 DOM
   */
  inputAttach: [Boolean, String, Object],
  /**
   * @zh textarea 独有最大行数
   */
  maxRows: {
    type: [Number, String],
    validator: (v) => !isNaN(parseFloat(v))
  },
  /**
   * @zh 控件的值
   */
  controlValue: null,
  /**
   * @zh 输入框的值
   */
  modelValue: null,
  /**
   * @zh 输入框 name
   */
  name: String,
  /**
   * @zh textarea 独有不允许重置大小
   */
  noResize: Boolean,
  /**
   * @zh 持续显示的计数器
   */
  persistentCounter: Boolean,
  /**
   * @zh 占位符内容
   */
  placeholder: String,
  /**
   * @zh textarea 独有最小行数
   */
  rows: {
    type: [Number, String],
    default: 5,
    validator: (v) => !isNaN(parseFloat(v))
  },
  /**
   * @zh 输入框类型
   */
  type: {
    type: String,
    default: "text"
  },
  /**
   * @zh 宽度值
   */
  width: [String, Number],
  ...makeInputControlProps()
});
const InputEmits = {
  ...FormControlEmits,
  ...InputControlEmits,
  "update:modelValue": (_) => true,
  "update:controlValue": (_) => true
};
const Input = genericComponent()({
  name: "VeInput",
  directives: {
    Intersect
  },
  props: makeInputProps(),
  emits: InputEmits,
  setup(props, {
    attrs,
    slots,
    emit
  }) {
    const vm = getCurrentInstance("VeInput");
    const inputControlRef = ref();
    const formControlRef = ref();
    const controlHeight = ref();
    const controlWidth = ref(props.width);
    const model = useProxiedModel(props, "modelValue");
    const controlValue = vm.vnode && propIsDefined(vm.vnode, "controlValue") ? useProxiedModel(props, "controlValue") : model;
    const id = computed(() => props.id || `ve-input-${getUid()}`);
    const internalDirty = ref(false);
    const isDirty = computed(() => {
      return internalDirty.value || !!model.value || dirtyTypes.includes(props.type);
    });
    const counterValue = computed(() => {
      return typeof props.counterValue === "function" ? props.counterValue(model.value) : (model.value || "").toString().length;
    });
    const max = computed(() => {
      if (attrs.maxlength)
        return attrs.maxlength;
      if (!props.counter || typeof props.counter !== "number" && typeof props.counter !== "string")
        return void 0;
      return props.counter;
    });
    function focus() {
      inputControlRef.value?.inputRef?.focus();
    }
    function blur() {
      inputControlRef.value?.inputRef?.blur();
    }
    function onIntersect(isIntersecting, entries) {
      if (!props.autofocus || !isIntersecting)
        return;
      entries[0].target?.focus?.();
    }
    const mirrorRef = ref();
    function resize() {
      if (!props.autoResize)
        return;
      nextTick(() => {
        if (!mirrorRef.value)
          return;
        if (props.type === "textarea") {
          const style = getComputedStyle(mirrorRef.value);
          const padding = (parseFloat(style.getPropertyValue("--ve-native-control---padding-top")) || 0) + (parseFloat(style.getPropertyValue("--ve-native-control---padding-bottom")) || 0);
          const lineHeight = parseFloat(style.lineHeight);
          const minHeight = parseFloat(props.rows) * lineHeight + padding;
          const maxHeight = parseFloat(props.maxRows) * lineHeight + padding || Infinity;
          controlHeight.value = Math.min(maxHeight, Math.max(minHeight, mirrorRef.value.scrollHeight));
        } else {
          controlWidth.value = Math.max(parseFloat(props.width ?? 100), mirrorRef.value.scrollWidth);
        }
      });
    }
    onMounted(resize);
    watch(model, resize);
    watch(() => props.rows, resize);
    watch(() => props.maxRows, resize);
    let observer;
    watch(mirrorRef, (val) => {
      if (val) {
        observer = new ResizeObserver(resize);
        observer.observe(mirrorRef.value);
      } else {
        observer?.disconnect();
      }
    });
    onBeforeUnmount(() => {
      observer?.disconnect();
    });
    function onControlClick(e) {
      focus();
      emit("click:control", e);
    }
    function onClear(e) {
      e.stopPropagation();
      focus();
      nextTick(() => {
        model.value = "";
        emit("click:clear", e);
      });
    }
    useRender(() => {
      const isTextarea = props.type === "textarea";
      const hasCounter = !!(slots.counter || props.counter || props.counterValue);
      const [inputControlProps] = filterInputControlProps(props);
      const [, nativeControlAttrs] = filterInputAttrs(attrs);
      const [formControlSlots] = filterFormControlSlots(slots);
      const [inputControlSlots] = filterInputControlSlots(slots);
      return _createVNode(FormControl, {
        "ref": formControlRef,
        "class": ["ve-input", {
          "ve-input--textarea": isTextarea,
          "ve-input--auto-resize": props.autoResize,
          "ve-input--no-resize": props.noResize || props.autoResize
        }],
        "labelId": id.value,
        "style": controlHeight.value ? {
          "--ve-form-control---height": convertToUnit(controlHeight.value)
        } : null,
        "name": props.name,
        "onClick:prepend": (e) => emit("click:prepend", e),
        "onClick:label": (e) => emit("click:label", e),
        "onClick:append": (e) => emit("click:append", e),
        "modelValue": controlValue.value,
        "onUpdate:modelValue": ($event) => controlValue.value = $event,
        "width": controlWidth.value
      }, {
        ...formControlSlots,
        default: ({
          isDisabled,
          isReadonly
        }) => {
          return _createVNode(InputControl, _mergeProps(inputControlProps, {
            "ref": inputControlRef,
            "onMousedown": (e) => {
              if (e.target === inputControlRef.value?.inputRef)
                return;
              e.preventDefault();
            },
            "dirty": !!model.value,
            "active": isDirty.value,
            "onClick:clear": onClear,
            "onClick:prependInner": (e) => emit("click:prepend-inner", e),
            "onClick:prefix": (e) => emit("click:prefix", e),
            "onClick:suffix": (e) => emit("click:suffix", e),
            "onClick:appendInner": (e) => emit("click:append-inner", e),
            "onClick:control": onControlClick,
            "onUpdate:active": (val) => internalDirty.value = val,
            "role": "textbox"
          }), {
            ...inputControlSlots,
            default: (slotProps) => {
              const {
                inputRef,
                focus: focus2,
                blur: blur2,
                props: nativeControlProps
              } = slotProps;
              if (isTextarea) {
                return _createVNode(_Fragment, null, [slots.default?.(slotProps), IN_BROWSER && _createVNode(Teleport, {
                  "disabled": !props.inputAttach,
                  "to": typeof props.inputAttach === "boolean" ? null : props.inputAttach
                }, {
                  default: () => [_withDirectives(_createVNode("textarea", _mergeProps({
                    "onUpdate:modelValue": ($event) => model.value = $event,
                    "autofocus": props.autofocus,
                    "disabled": isDisabled.value,
                    "id": id.value,
                    "name": props.name,
                    "onFocus": focus2,
                    "onBlur": blur2,
                    "placeholder": props.placeholder,
                    "readonly": isReadonly.value,
                    "ref": inputRef,
                    "rows": props.rows
                  }, nativeControlProps, nativeControlAttrs), null), [[_vModelText, model.value], [_resolveDirective("intersect"), {
                    handler: onIntersect
                  }, null, {
                    once: true
                  }]]), props.autoResize && _withDirectives(_createVNode("textarea", _mergeProps({
                    "class": "ve-input__textarea-mirror",
                    "onUpdate:modelValue": ($event) => model.value = $event,
                    "ref": mirrorRef,
                    "readonly": true,
                    "aria-hidden": "true"
                  }, nativeControlProps), null), [[_vModelText, model.value]])]
                })]);
              } else {
                return _createVNode(_Fragment, null, [slots.default?.(slotProps), IN_BROWSER && _createVNode(Teleport, {
                  "disabled": !props.inputAttach,
                  "to": typeof props.inputAttach === "boolean" ? null : props.inputAttach
                }, {
                  default: () => [_withDirectives(_createVNode("input", _mergeProps({
                    "onUpdate:modelValue": ($event) => model.value = $event,
                    "onInput": (e) => {
                      if (mirrorRef.value) {
                        mirrorRef.value.textContent = e.target.value;
                        resize();
                      }
                    },
                    "autofocus": props.autofocus,
                    "disabled": isDisabled.value,
                    "id": id.value,
                    "name": props.name,
                    "onFocus": focus2,
                    "onBlur": blur2,
                    "placeholder": props.placeholder,
                    "readonly": isReadonly.value,
                    "ref": inputRef,
                    "type": props.type
                  }, nativeControlProps, nativeControlAttrs), null), [[_resolveDirective("intersect"), {
                    handler: onIntersect
                  }, null, {
                    once: true
                  }], [_vModelDynamic, model.value]]), props.autoResize && _createVNode("span", _mergeProps({
                    "class": "ve-input__input-mirror",
                    "ref": mirrorRef,
                    "aria-hidden": "true"
                  }, nativeControlProps), [model.value])]
                })]);
              }
            }
          });
        },
        details: hasCounter ? () => {
          return _createVNode(_Fragment, null, [_createVNode("span", null, null), _createVNode(Counter, {
            "active": props.persistentCounter || isDirty.value,
            "value": counterValue.value,
            "max": max.value
          }, {
            default: slots.counter
          })]);
        } : formControlSlots?.details
      });
    });
    return {
      formControlRef,
      inputControlRef,
      blur,
      focus
    };
  }
});
export {
  Input,
  InputEmits,
  makeInputProps
};
//# sourceMappingURL=input.mjs.map
