|
@@ -1,38 +1,50 @@
|
|
|
-<script setup lang="ts">
|
|
|
-import { reactive } from 'vue'
|
|
|
+<script setup lang="ts" generic="T extends string | string[]">
|
|
|
import type { LoadingManager, Texture } from 'three'
|
|
|
-import { useTexture, type UseTextureReturn } from './index'
|
|
|
+import { useTexture2 } from './index'
|
|
|
+import { computed, defineEmits, defineProps } from 'vue'
|
|
|
+import { whenever } from '@vueuse/core'
|
|
|
|
|
|
const props = defineProps<{
|
|
|
/**
|
|
|
* Path or array of paths to texture(s)
|
|
|
- */
|
|
|
- path: string | string[]
|
|
|
+ */
|
|
|
+ path: T
|
|
|
/**
|
|
|
* Optional THREE.js LoadingManager
|
|
|
*/
|
|
|
manager?: LoadingManager
|
|
|
}>()
|
|
|
+
|
|
|
const emit = defineEmits<{
|
|
|
- (e: 'loaded'): void
|
|
|
- (e: 'error', error: Error): void
|
|
|
+ loaded: [texture: T extends string ? Texture : Texture[]]
|
|
|
+ error: [error: T extends string ? unknown : unknown[]] // this is unknown because TextureLoader's error type is unknown
|
|
|
}>()
|
|
|
|
|
|
-// Type guard to handle the union type
|
|
|
-const textureData = Array.isArray(props.path)
|
|
|
- ? reactive<UseTextureReturn<Texture[]>>(useTexture(props.path, props.manager))
|
|
|
- : reactive<UseTextureReturn<Texture>>(useTexture(props.path, props.manager))
|
|
|
+const state = useTexture2(props.path, { manager: props.manager })
|
|
|
+
|
|
|
+const isMultiple = (x: ReturnType<typeof useTexture2<string, any>> | ReturnType<typeof useTexture2<string[], any>>): x is ReturnType<typeof useTexture2<string[], any>> => Array.isArray(x)
|
|
|
+
|
|
|
+const errorOrErrors = computed(() =>
|
|
|
+ (isMultiple(state) ? state.map(({ error }) => error.value) : state.error.value),
|
|
|
+)
|
|
|
+const hasError = computed(() =>
|
|
|
+ isMultiple(state) ? state.some(({ error }) => error.value) : !!state.error.value,
|
|
|
+)
|
|
|
+whenever(hasError, () => {
|
|
|
+ emit('error', errorOrErrors.value as unknown as T extends string ? unknown : unknown[])
|
|
|
+})
|
|
|
|
|
|
-// Handle loading state
|
|
|
-textureData.promise
|
|
|
- .then(() => emit('loaded'))
|
|
|
- .catch(err => emit('error', err))
|
|
|
+const isReady = computed(() => {
|
|
|
+ return isMultiple(state) ? state.every(({ isReady }) => isReady.value) : !!state.isReady
|
|
|
+})
|
|
|
+const dataOrDataArray = computed(() =>
|
|
|
+ isMultiple(state) ? state.map(({ state }) => state.value) : state.state.value,
|
|
|
+)
|
|
|
+whenever(isReady, () => {
|
|
|
+ emit('loaded', dataOrDataArray.value as unknown as T extends string ? Texture : Texture[])
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <slot
|
|
|
- :data="textureData.data"
|
|
|
- :is-loading="textureData.isLoading"
|
|
|
- :error="textureData.error"
|
|
|
- ></slot>
|
|
|
+ <slot v-bind="state"></slot>
|
|
|
</template>
|