composables.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {
  2. customRef,
  3. DeepReadonly,
  4. onBeforeUnmount,
  5. readonly,
  6. Ref,
  7. ref,
  8. useContext,
  9. watch,
  10. wrapProperty,
  11. } from "@nuxtjs/composition-api"
  12. import { Observable, Subscription } from "rxjs"
  13. export const useNuxt = wrapProperty("$nuxt")
  14. export function useReadonlyStream<T>(
  15. stream$: Observable<T>,
  16. initialValue: T
  17. ): Ref<DeepReadonly<T>> {
  18. let sub: Subscription | null = null
  19. onBeforeUnmount(() => {
  20. if (sub) {
  21. sub.unsubscribe()
  22. }
  23. })
  24. const targetRef = ref(initialValue) as Ref<T>
  25. sub = stream$.subscribe((value) => {
  26. targetRef.value = value
  27. })
  28. return readonly(targetRef)
  29. }
  30. export function useStream<T>(
  31. stream$: Observable<T>,
  32. initialValue: T,
  33. setter: (val: T) => void
  34. ) {
  35. let sub: Subscription | null = null
  36. onBeforeUnmount(() => {
  37. if (sub) {
  38. sub.unsubscribe()
  39. }
  40. })
  41. return customRef((track, trigger) => {
  42. let value = initialValue
  43. sub = stream$.subscribe((val) => {
  44. value = val
  45. trigger()
  46. })
  47. return {
  48. get() {
  49. track()
  50. return value
  51. },
  52. set(value: T) {
  53. trigger()
  54. setter(value)
  55. },
  56. }
  57. })
  58. }
  59. export function pluckRef<T, K extends keyof T>(ref: Ref<T>, key: K): Ref<T[K]> {
  60. return customRef((track, trigger) => {
  61. const stopWatching = watch(ref, (newVal, oldVal) => {
  62. if (newVal[key] !== oldVal[key]) {
  63. trigger()
  64. }
  65. })
  66. onBeforeUnmount(() => {
  67. stopWatching()
  68. })
  69. return {
  70. get() {
  71. track()
  72. return ref.value[key]
  73. },
  74. set(value: T[K]) {
  75. trigger()
  76. ref.value = Object.assign(ref.value, { [key]: value })
  77. },
  78. }
  79. })
  80. }
  81. export function pluckMultipleFromRef<T, K extends Array<keyof T>>(
  82. sourceRef: Ref<T>,
  83. keys: K
  84. ): { [key in K[number]]: Ref<T[key]> } {
  85. return Object.fromEntries(keys.map((x) => [x, pluckRef(sourceRef, x)])) as any
  86. }
  87. /**
  88. * A composable that provides the ability to run streams
  89. * and subscribe to them and respect the component lifecycle.
  90. */
  91. export function useStreamSubscriber() {
  92. const subs: Subscription[] = []
  93. const runAndSubscribe = <T>(
  94. stream: Observable<T>,
  95. next?: (value: T) => void,
  96. error?: (e: any) => void,
  97. complete?: () => void
  98. ) => {
  99. const sub = stream.subscribe({
  100. next,
  101. error,
  102. complete: () => {
  103. if (complete) complete()
  104. subs.splice(subs.indexOf(sub), 1)
  105. },
  106. })
  107. subs.push(sub)
  108. }
  109. onBeforeUnmount(() => {
  110. subs.forEach((sub) => sub.unsubscribe())
  111. })
  112. return {
  113. subscribeToStream: runAndSubscribe,
  114. }
  115. }
  116. export function useI18n() {
  117. const {
  118. app: { i18n },
  119. } = useContext()
  120. return i18n.t.bind(i18n)
  121. }
  122. export function useToast() {
  123. const { $toast } = useContext()
  124. return $toast
  125. }