DynamicInitializer.vue 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { useEventListener } from '@vueuse/core'
  4. import { markRaw, shallowRef } from 'vue'
  5. import { Events } from './manage.ts'
  6. import type { DestroyComponentData, PushComponentData } from './types.ts'
  7. import type { TransitionProps } from 'vue'
  8. const props = defineProps<{
  9. /**
  10. * Name of a group of components that will be pushed to with unique ID.
  11. */
  12. name: string
  13. /**
  14. * Transition, if any.
  15. */
  16. transition?: TransitionProps
  17. }>()
  18. const components = shallowRef<PushComponentData[]>([])
  19. useEventListener(
  20. window,
  21. Events.Push,
  22. ({ detail }: CustomEvent<PushComponentData>) => {
  23. if (detail.name !== props.name) return
  24. components.value = [
  25. ...components.value,
  26. {
  27. ...detail,
  28. cmp: markRaw(detail.cmp),
  29. },
  30. ]
  31. },
  32. )
  33. useEventListener(
  34. window,
  35. Events.Destroy,
  36. ({ detail }: CustomEvent<DestroyComponentData>) => {
  37. if (detail.name !== props.name) return
  38. if (!detail.id) {
  39. components.value = []
  40. return
  41. }
  42. components.value = components.value.filter(
  43. (item) => !(item.name === detail.name && item.id === detail.id),
  44. )
  45. },
  46. )
  47. </script>
  48. <template>
  49. <TransitionGroup v-if="transition" v-bind="transition">
  50. <Component
  51. :is="cmp"
  52. v-for="{ cmp, name: cmpName, id, props: cmpProps } in components"
  53. :key="`${cmpName}-${id}`"
  54. v-bind="cmpProps"
  55. />
  56. </TransitionGroup>
  57. <template v-else-if="!$slots.default">
  58. <Component
  59. :is="cmp"
  60. v-for="{ cmp, name: cmpName, id, props: cmpProps } in components"
  61. :key="`${cmpName}-${id}`"
  62. v-bind="cmpProps"
  63. />
  64. </template>
  65. <slot v-else :components="components" />
  66. </template>