Skip to content
Snippets Groups Projects
AEditDialog.vue 1.96 KiB
Newer Older
<template>
  <ADialog ref="dialog" is-modal class="tw-max-w-2xl tw-w-full">
    <form :id="id" @submit.prevent.stop="doSave">
      <slot />
    </form>

    <template #footer>
      <slot name="footer" :close="close">
        <div class="tw-flex tw-items-center tw-gap-3">
          <button
            type="submit"
            class="btn tw-bg-aura-primary tw-text-white"
            :form="id"
            :disabled="isSaving || canSave === false"
          >
            <Loading v-if="isSaving" class="tw-h-1.5 tw-mr-1" />
            {{ saveLabel ?? t('save') }}
          </button>
          <button type="button" class="btn" :disabled="isSaving" @click="dialog.close()">
            {{ cancelLabel ?? t('cancel') }}
          </button>
          <slot name="footer-buttons-extra" :is-saving="isSaving" />
      </slot>
    </template>

    <template v-for="(_, name) in slots" #[name]="slotProps">
      <slot :name="name" v-bind="slotProps || {}" />
    </template>
  </ADialog>
</template>
<script setup lang="ts">
import { ref, useSlots } from 'vue'
import { useI18n } from '@/i18n'
import { useId } from '@/util'
import ADialog from '@/components/generic/ADialog.vue'
import Loading from '@/components/generic/Loading.vue'

defineOptions({ compatConfig: { MODE: 3 } })

const props = withDefaults(
  defineProps<{
    save?: () => unknown
    canSave?: boolean | undefined
    saveLabel?: string
    cancelLabel?: string
  }>(),
  {
    save: undefined,
    canSave: undefined,
    saveLabel: undefined,
    cancelLabel: undefined,
  },
)
const { t } = useI18n()
const id = useId('dialog-form')
const dialog = ref()
const isSaving = ref(false)

function open() {
  dialog.value.open()
}

function close() {
  dialog.value.close()
}

async function doSave() {
  const save = props?.save
  if (!save) return
  isSaving.value = true
  try {
    await save()
  } finally {
    isSaving.value = false
  }
}

defineExpose({
  open,
  close,
})
</script>