Răsfoiți Sursa

made component generic

Tino Koch 5 luni în urmă
părinte
comite
c4cb367b35

+ 2 - 2
playground/vue/src/pages/composables/useTexture/ObjectUseTextureComponent.vue

@@ -9,7 +9,7 @@ const paths = [
 </script>
 
 <template>
-  <UseTexture v-slot="{ data: texture }" :path="paths">
+  <UseTexture v-slot="states" :path="paths">
     <TresMesh :position="[-3, 1, 0]">
       <Html transform position-y="1.5">
         <span class="text-xs bg-white p-2 rounded-md">
@@ -17,7 +17,7 @@ const paths = [
         </span>
       </Html>
       <TresSphereGeometry :args="[1, 32, 32]" />
-      <TresMeshStandardMaterial v-if="texture" :map="texture[0]" :displacement-map="texture[1]" :displacement-scale="0.1" />
+      <TresMeshStandardMaterial v-if="states[0].state.value && states[1].state.value" :map="states[0].state.value" :displacement-map="states[1].state.value" :displacement-scale="0.1" />
     </TresMesh>
   </UseTexture>
 </template>

+ 1 - 1
playground/vue/src/pages/composables/useTexture/index.vue

@@ -48,7 +48,7 @@ const gl = {
         </TresMesh>
       </template>
     </Suspense>
-    <ObjectUseTextureComponent />
+    <ObjectUseTextureComponent @loaded="console.log('👍👍👍👍loaded!')" @error="console.log('👎👎👎👎error!')" />
     <ObjectSyncLoadSimpleTexture />
     <ObjectSyncLoadMultipleTexture />
   </TresCanvas>

+ 32 - 20
src/composables/useTexture/component.vue

@@ -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>

+ 3 - 3
src/composables/useTexture/index.ts

@@ -91,11 +91,11 @@ export function useTexture2<T extends string | string[], Shallow extends boolean
     },
   )
 
-  if (Array.isArray(path)) {
-    return path.map(path => makeComposable(path)) as T extends string ? never : UseAsyncStateReturn<Texture, [], true>[]
+  if (typeof path === 'string') {
+    return makeComposable(path) as T extends string ? UseAsyncStateReturn<Texture, [], true> : never
   }
 
-  return makeComposable(path) as T extends string ? UseAsyncStateReturn<Texture, [], true> : never
+  return path.map(path => makeComposable(path)) as T extends string ? never : UseAsyncStateReturn<Texture, [], true>[]
 }
 
 export function useTexture(path: string, manager?: LoadingManager): UseTextureReturn<Texture> & Promise<UseTextureReturn<Texture>>