<template>
  <div
    class="text-input text-start"
    :class="{
      'input-group': !floatingLabel,
      flush: flush,
      'form-floating': floatingLabel,
      'form-filled': !!modelValue,
    }"
  >
    <label class="input-group-text" :for="id" v-if="!!label && !floatingLabel">{{ label }}</label>
    <input
      :id="id"
      :type="type"
      class="form-control"
      v-bind="$attrs"
      :placeholder="placeholderText"
      :value="modelValue"
      :maxlength="maxlength"
      :max="max"
      :min="min"
      :pattern="pattern"
      ref="textInput"
      @focus="onFocus($event)"
      @blur="onBlur($event)"
      @input="onInput($event)"
      @keydown="onKeyDown($event)"
    />
    <label :for="id" v-if="!!label && floatingLabel">{{ label }}</label>
    <button
      v-if="hasAction"
      type="button"
      class="btn btn-outline-secondary"
      :class="{ disabled: actionDisabled }"
      @click="onAction()"
      :disabled="actionDisabled"
    >
      <slot name="action-content">
        {{ actionText }}
      </slot>
    </button>
  </div>
</template>

<script lang="ts">
import { useIds } from '@/composables';
const { getId } = useIds();
</script>

<script setup lang="ts">
import { computed, ref } from 'vue';

defineOptions({ inheritAttrs: false });
const props = defineProps({
  type: {
    type: String,
    default: 'text',
  },
  id: {
    type: String,
    default: () => getId('input'),
  },
  hasAction: {
    type: Boolean,
    default: false,
  },
  actionDisabled: {
    type: Boolean,
    default: false,
  },
  flush: {
    type: Boolean,
    default: false,
  },
  max: Number,
  min: Number,
  maxlength: Number,
  pattern: String,
  regex: RegExp,
  actionText: String,
  label: String,
  modelValue: String,
  placeholder: String,
  floatingLabel: Boolean,
});
const emit = defineEmits(['update:modelValue', 'onAction', 'keydown.enter', 'focus', 'blur']);

const placeholderText = computed(() => props.placeholder || '');
const onInput = (e: any) => emit('update:modelValue', e.target.value);
const textInput = ref<HTMLInputElement | null>(null);

const getTextValue = () => textInput.value?.value || '';

const focus = () => textInput.value?.focus();
const blur = () => textInput.value?.blur();
const onFocus = (e: any) => emit('focus', e);
const onBlur = (e: any) => emit('blur', e);
const onAction = () => {
  if (!props.actionDisabled) {
    emit('onAction', getTextValue());
  }
};
const onKeyDown = (e: any) => {
  if (e.which === 13) {
    onEnter();
  } else if (e.which === 8 || e.which === 46) {
    return true;
  } else {
    const val = e.target.value + e.key;
    if (!!props.regex && !props.regex.test(val)) {
      e.preventDefault();
      return false;
    }
  }
  return true;
};
const onEnter = () => {
  if (!props.actionDisabled) {
    emit('keydown.enter', getTextValue());
  }
};

defineExpose({ focus, blur });
</script>

<style lang="scss">
@import '../../styles/mixins';

.text-input {
  &.input-group.text-start,
  &.form-floating.text-start {
    &.flush {
      label.input-group-text {
        border-radius: 0;
        border-left-width: 0;
      }
      .form-control {
        border-radius: 0;
        border-right-width: 0;
      }
    }
  }
  &.form-floating.text-start {
    .form-control {
      min-height: 40px;
      height: 40px;
      padding: 0.5rem 0.75rem 0.25rem;
      ~ label {
        top: -8px;
      }
      &:focus ~ label {
        opacity: 0.6;
        top: -15px;
      }
    }
    &.form-filled {
      .form-control ~ label {
        opacity: 0.6;
        top: -15px;
      }
    }
    &:not(.form-filled) {
      .form-control ~ label {
        opacity: 0.8;
      }
    }
  }
  label.input-group-text {
    @include noTextSelect();
  }
}
</style>
