drawer.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <script lang="ts" setup>
  2. import type { DrawerProps, ExtendedDrawerApi } from './drawer';
  3. import { usePriorityValue } from '@vben-core/composables';
  4. import { Info, X } from '@vben-core/icons';
  5. import {
  6. Sheet,
  7. SheetClose,
  8. SheetContent,
  9. SheetDescription,
  10. SheetFooter,
  11. SheetHeader,
  12. SheetTitle,
  13. VbenButton,
  14. VbenIconButton,
  15. VbenLoading,
  16. VbenTooltip,
  17. VisuallyHidden,
  18. } from '@vben-core/shadcn-ui';
  19. import { cn } from '@vben-core/shared';
  20. interface Props extends DrawerProps {
  21. class?: string;
  22. contentClass?: string;
  23. drawerApi?: ExtendedDrawerApi;
  24. }
  25. const props = withDefaults(defineProps<Props>(), {
  26. class: '',
  27. contentClass: '',
  28. drawerApi: undefined,
  29. });
  30. const state = props.drawerApi?.useStore?.();
  31. const title = usePriorityValue('title', props, state);
  32. const description = usePriorityValue('description', props, state);
  33. const titleTooltip = usePriorityValue('titleTooltip', props, state);
  34. const showFooter = usePriorityValue('footer', props, state);
  35. const showLoading = usePriorityValue('loading', props, state);
  36. const closable = usePriorityValue('closable', props, state);
  37. const modal = usePriorityValue('modal', props, state);
  38. const confirmLoading = usePriorityValue('confirmLoading', props, state);
  39. const cancelText = usePriorityValue('cancelText', props, state);
  40. const confirmText = usePriorityValue('confirmText', props, state);
  41. </script>
  42. <template>
  43. <Sheet
  44. :modal="modal"
  45. :open="state?.isOpen"
  46. @update:open="() => drawerApi?.close()"
  47. >
  48. <SheetContent :class="cn('flex w-[520px] flex-col', props.class, {})">
  49. <SheetHeader
  50. :class="
  51. cn('!flex flex-row items-center justify-between border-b px-6 py-5', {
  52. 'px-4 py-3': closable,
  53. })
  54. "
  55. >
  56. <div>
  57. <SheetTitle v-if="title">
  58. <slot name="title">
  59. {{ title }}
  60. <VbenTooltip v-if="titleTooltip" side="right">
  61. <template #trigger>
  62. <Info class="inline-flex size-5 cursor-pointer pb-1" />
  63. </template>
  64. {{ titleTooltip }}
  65. </VbenTooltip>
  66. </slot>
  67. </SheetTitle>
  68. <SheetDescription v-if="description" class="mt-1 text-xs">
  69. <slot name="description">
  70. {{ description }}
  71. </slot>
  72. </SheetDescription>
  73. </div>
  74. <VisuallyHidden v-if="!title || !description">
  75. <SheetTitle v-if="!title" />
  76. <SheetDescription v-if="!description" />
  77. </VisuallyHidden>
  78. <div class="flex-center">
  79. <slot name="extra"></slot>
  80. <SheetClose
  81. v-if="closable"
  82. as-child
  83. class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
  84. >
  85. <VbenIconButton>
  86. <X class="size-4" />
  87. </VbenIconButton>
  88. </SheetClose>
  89. </div>
  90. </SheetHeader>
  91. <div
  92. :class="
  93. cn('relative flex-1 p-3', contentClass, {
  94. 'overflow-y-auto': !showLoading,
  95. })
  96. "
  97. >
  98. <VbenLoading v-if="showLoading" class="size-full" spinning />
  99. <slot></slot>
  100. </div>
  101. <SheetFooter
  102. v-if="showFooter"
  103. class="w-full items-center border-t p-2 px-3"
  104. >
  105. <slot name="prepend-footer"></slot>
  106. <slot name="footer">
  107. <VbenButton
  108. size="sm"
  109. variant="ghost"
  110. @click="() => drawerApi?.onCancel()"
  111. >
  112. <slot name="cancelText">
  113. {{ cancelText }}
  114. </slot>
  115. </VbenButton>
  116. <VbenButton
  117. :loading="confirmLoading"
  118. size="sm"
  119. @click="() => drawerApi?.onConfirm()"
  120. >
  121. <slot name="confirmText">
  122. {{ confirmText }}
  123. </slot>
  124. </VbenButton>
  125. </slot>
  126. <slot name="append-footer"></slot>
  127. </SheetFooter>
  128. </SheetContent>
  129. </Sheet>
  130. </template>