Skip to content
Snippets Groups Projects
ALinkEditor.vue 2.49 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
    
      <fieldset class="tw-flex tw-gap-3 tw-items-start tw-flex-wrap">
    
        <FormGroup
          v-slot="attrs"
    
          class="tw-m-0 tw-w-32 tw-flex-none"
    
          :errors="getFieldErrors(errors, 'typeId')"
        >
          <select
            v-model="link.typeId"
            v-bind="attrs"
    
            class="tw-truncate"
    
            :required="deletable"
            :aria-label="t('link.fields.typeId')"
            @blur="emit('check')"
          >
            <option :value="null" />
            <option v-for="type in activeLinkTypes" :key="type.id" :value="type.id">
              {{ type.name }}
            </option>
            <optgroup v-if="inactiveLinkTypes.length > 0" :label="t('linkType.inactive')">
              <option v-for="type in inactiveLinkTypes" :key="type.id" :value="type.id">
                {{ type.name }}
              </option>
            </optgroup>
          </select>
        </FormGroup>
    
        <FormGroup
          v-slot="attrs"
          class="tw-m-0 tw-min-w-24 tw-flex-1"
          :errors="getFieldErrors(errors, 'url')"
        >
    
          <input
            v-bind="attrs"
            ref="urlEl"
            v-model="link.url"
            type="url"
            :required="deletable"
            :aria-label="t('link.fields.url')"
            :placeholder="t('link.urlExample')"
            class="user-invalid:tw-text-rose-600"
            @blur="onURLBlur"
          />
        </FormGroup>
    
        <button
    
          type="button"
    
          class="btn btn-sm btn-default tw-size-9 tw-translate-y-px tw-flex-none"
    
          :title="t('delete')"
          @click="emit('delete')"
        >
          <icon-system-uicons-trash />
          <span class="tw-sr-only">{{ t('delete') }}</span>
        </button>
      </fieldset>
    </template>
    
    <script lang="ts" setup>
    import { ErrorDetail } from '@rokoli/bnb'
    import { computed, ref } from 'vue'
    
    import { useI18n } from '@/i18n'
    import { useLinkTypeStore } from '@/stores'
    import { Link } from '@/types'
    import FormGroup from '@/components/generic/FormGroup.vue'
    import { getFieldErrors } from '@/form'
    
    defineOptions({ compatConfig: { MODE: 3 } })
    
    const link = defineModel<Link>({ required: true })
    const props = defineProps<{ deletable?: boolean; errors: ErrorDetail[] }>()
    const emit = defineEmits<{ check: []; delete: [] }>()
    const { t } = useI18n()
    const linkTypeStore = useLinkTypeStore()
    
    const urlEl = ref<HTMLInputElement>()
    const activeLinkTypes = computed(() => linkTypeStore.items.filter((l) => l.isActive))
    const inactiveLinkTypes = computed(() => linkTypeStore.items.filter((l) => !l.isActive))
    
    function onURLBlur() {
      if (props.deletable || urlEl.value?.checkValidity()) emit('check')
    }
    </script>