import { ref, computed, onMounted, watch, onBeforeUnmount, createVNode, mergeProps, Fragment, Teleport, withDirectives, vModelText, resolveDirective, vModelDynamic, nextTick } from "vue";
import "./styles/input.scss";
import { makeInputControlProps, InputControlEmits, filterInputControlProps, filterInputControlSlots, InputControl } from "../input-control/input-control.mjs";
import { FormControlEmits, filterFormControlSlots, FormControl } from "../form-control/form-control.mjs";
import { useProxiedModel } from "../../composables/proxied-model/index.mjs";
import { Intersect } from "../../directives/intersect/index.mjs";
import { Counter } from "../counter/counter.mjs";
import { propsFactory, getCurrentInstance, getUid, useRender, filterInputAttrs, convertToUnit, IN_BROWSER } from "../../utils/dist/index.mjs";
import { genericComponent, propIsDefined } from "../../utils/define-component.mjs";
const dirtyTypes = ["color", "file", "time", "date", "datetime-local", "week", "month"];
const makeInputProps = propsFactory({
  autofocus: Boolean,
  autoResize: Boolean,
  counter: [Boolean, Number, String],
  counterValue: Function,
  id: String,
  inputAttach: [Boolean, String, Object],
  maxRows: {
    type: [Number, String],
    validator: (v) => !isNaN(parseFloat(v))
  },
  controlValue: null,
  modelValue: null,
  name: String,
  noResize: Boolean,
  persistentCounter: Boolean,
  placeholder: String,
  rows: {
    type: [Number, String],
    default: 5,
    validator: (v) => !isNaN(parseFloat(v))
  },
  type: {
    type: String,
    default: "text"
  },
  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() {
      var _a, _b;
      (_b = (_a = inputControlRef.value) == null ? void 0 : _a.inputRef) == null ? void 0 : _b.focus();
    }
    function blur() {
      var _a, _b;
      (_b = (_a = inputControlRef.value) == null ? void 0 : _a.inputRef) == null ? void 0 : _b.blur();
    }
    function onIntersect(isIntersecting, entries) {
      var _a, _b;
      if (!props.autofocus || !isIntersecting)
        return;
      (_b = (_a = entries[0].target) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
    }
    const mirrorRef = ref();
    function resize() {
      if (!props.autoResize)
        return;
      nextTick(() => {
        var _a;
        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((_a = props.width) != null ? _a : 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 == null ? void 0 : observer.disconnect();
      }
    });
    onBeforeUnmount(() => {
      observer == null ? void 0 : 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) => {
              var _a;
              if (e.target === ((_a = inputControlRef.value) == null ? void 0 : _a.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) => {
              var _a, _b;
              const {
                inputRef,
                focus: focus2,
                blur: blur2,
                props: nativeControlProps
              } = slotProps;
              if (isTextarea) {
                return createVNode(Fragment, null, [(_a = slots.default) == null ? void 0 : _a.call(slots, 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, [(_b = slots.default) == null ? void 0 : _b.call(slots, 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 == null ? void 0 : formControlSlots.details
      });
    });
    return {
      formControlRef,
      inputControlRef,
      blur,
      focus
    };
  }
});
export {
  Input,
  InputEmits,
  makeInputProps
};
//# sourceMappingURL=input.mjs.map
