refactor: dep cleanup
This commit is contained in:
@@ -48,7 +48,6 @@
|
||||
"@proj-airi/server-sdk": "workspace:*",
|
||||
"@proj-airi/stage-ui": "workspace:^",
|
||||
"@proj-airi/ui": "workspace:^",
|
||||
"@ricky0123/vad-web": "^0.0.29",
|
||||
"@stdlib/string-base-kebabcase": "^0.2.2",
|
||||
"@tresjs/cientos": "^5.1.0",
|
||||
"@tresjs/core": "^5.1.0",
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"@proj-airi/stage-ui-three": "workspace:^",
|
||||
"@proj-airi/ui": "workspace:^",
|
||||
"@proj-airi/ui-transitions": "workspace:^",
|
||||
"@ricky0123/vad-web": "^0.0.29",
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@stdlib/string-base-kebabcase": "^0.2.2",
|
||||
"@tresjs/cientos": "^5.1.0",
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"@pixiv/three-vrm-animation": "^3.4.4",
|
||||
"@pixiv/three-vrm-core": "^3.4.4",
|
||||
"@proj-airi/stage-shared": "workspace:*",
|
||||
"@proj-airi/tresjs": "workspace:*",
|
||||
"@tresjs/cientos": "^5.1.0",
|
||||
"@tresjs/core": "^5.1.0",
|
||||
"@tresjs/post-processing": "^3.1.0",
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"culori": "^4.0.2",
|
||||
"pinia": "^3.0.4",
|
||||
|
||||
@@ -13,8 +13,8 @@ import type { DirectionalLight, SphericalHarmonics3, Texture, WebGLRenderTarget
|
||||
import type { Vec3 } from '../stores/model-store'
|
||||
|
||||
import { withBase } from '@proj-airi/stage-shared'
|
||||
import { EffectComposerPmndrs, HueSaturationPmndrs } from '@proj-airi/tresjs/post-processing'
|
||||
import { TresCanvas } from '@tresjs/core'
|
||||
import { EffectComposerPmndrs, HueSaturationPmndrs } from '@tresjs/post-processing'
|
||||
import { useElementBounding } from '@vueuse/core'
|
||||
import { formatHex } from 'culori'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
@@ -80,9 +80,6 @@
|
||||
"@proj-airi/ui": "workspace:^",
|
||||
"@ricky0123/vad-web": "^0.0.29",
|
||||
"@shikijs/rehype": "^3.15.0",
|
||||
"@tresjs/cientos": "^5.1.0",
|
||||
"@tresjs/core": "^5.1.0",
|
||||
"@tresjs/post-processing": "^3.1.0",
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"@vueuse/motion": "^3.0.3",
|
||||
"@vueuse/shared": "^14.0.0",
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useTresContext } from '@tresjs/core'
|
||||
import { until } from '@vueuse/core'
|
||||
import { onMounted, shallowRef, toRef } from 'vue'
|
||||
|
||||
import * as THREE from 'three'
|
||||
|
||||
const props = defineProps<{
|
||||
directionalLight?: THREE.DirectionalLight | null
|
||||
}>()
|
||||
|
||||
const { scene } = useTresContext()
|
||||
const directionalLightRef = toRef(() => props.directionalLight)
|
||||
const lightHelper = shallowRef<THREE.DirectionalLightHelper>()
|
||||
|
||||
onMounted(async () => {
|
||||
await until(directionalLightRef).toBeTruthy()
|
||||
lightHelper.value = new THREE.DirectionalLightHelper(directionalLightRef.value!, 1)
|
||||
scene.value.add(lightHelper.value)
|
||||
})
|
||||
|
||||
if (import.meta.hot) {
|
||||
// Ensure cleanup on HMR
|
||||
import.meta.hot.dispose(() => {
|
||||
try {
|
||||
if (lightHelper.value) {
|
||||
lightHelper.value.dispose()
|
||||
scene.value.remove(lightHelper.value)
|
||||
lightHelper.value = undefined
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error during DirectionalLightHelper cleanup:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot />
|
||||
</template>
|
||||
@@ -1,41 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useTresContext } from '@tresjs/core'
|
||||
import { until } from '@vueuse/core'
|
||||
import { onMounted, shallowRef, toRef } from 'vue'
|
||||
|
||||
import * as THREE from 'three'
|
||||
|
||||
const props = defineProps<{
|
||||
hemisphereLight?: THREE.HemisphereLight | null
|
||||
}>()
|
||||
|
||||
const { scene } = useTresContext()
|
||||
const hemisphereLightRef = toRef(() => props.hemisphereLight)
|
||||
const lightHelper = shallowRef<THREE.HemisphereLightHelper>()
|
||||
|
||||
onMounted(async () => {
|
||||
await until(hemisphereLightRef).toBeTruthy()
|
||||
lightHelper.value = new THREE.HemisphereLightHelper(hemisphereLightRef.value!, 1)
|
||||
scene.value.add(lightHelper.value)
|
||||
})
|
||||
|
||||
if (import.meta.hot) {
|
||||
// Ensure cleanup on HMR
|
||||
import.meta.hot.dispose(() => {
|
||||
try {
|
||||
if (lightHelper.value) {
|
||||
lightHelper.value.dispose()
|
||||
scene.value.remove(lightHelper.value)
|
||||
lightHelper.value = undefined
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error during HemisphereLightHelper cleanup:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot />
|
||||
</template>
|
||||
File diff suppressed because one or more lines are too long
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "@proj-airi/tresjs",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"description": "Shared Tres (effects, composables)",
|
||||
"author": {
|
||||
"name": "Moeru AI Project AIRI Team",
|
||||
"email": "airi@moeru.ai",
|
||||
"url": "https://github.com/moeru-ai"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/moeru-ai/airi.git",
|
||||
"directory": "packages/tresjs"
|
||||
},
|
||||
"exports": {
|
||||
"./post-processing": "./src/post-processing/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "vue-tsc --noEmit"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tresjs/cientos": ">=5.0.0 <6.0.0",
|
||||
"@tresjs/core": ">=5.0.0 <6.0.0",
|
||||
"postprocessing": ">=6.0.0 <7.0.0",
|
||||
"three": ">=0.180.0 <0.181.0",
|
||||
"vue": ">=3.5.0 <4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "^0.181.0",
|
||||
"vue-tsc": "^3.1.4"
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
<!--
|
||||
https://github.com/Tresjs/post-processing/blob/c89b5b4353d889d58da4dd6746e64b32a3f711ec/src/core/pmndrs/EffectComposerPmndrs.vue
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { EffectComposer } from 'postprocessing'
|
||||
import type { WebGLRenderer } from 'three'
|
||||
import type { InjectionKey, ShallowRef } from 'vue'
|
||||
|
||||
import WEBGL from 'three/examples/jsm/capabilities/WebGL.js'
|
||||
|
||||
import { useTres, useTresContext } from '@tresjs/core'
|
||||
import {
|
||||
DepthDownsamplingPass,
|
||||
EffectComposer as EffectComposerImpl,
|
||||
NormalPass,
|
||||
RenderPass,
|
||||
} from 'postprocessing'
|
||||
import { HalfFloatType } from 'three'
|
||||
import { computed, onUnmounted, provide, shallowRef, watch } from 'vue'
|
||||
|
||||
export const effectComposerInjectionKey: InjectionKey<ShallowRef<EffectComposer | null>> = Symbol('effectComposerPmndrs')
|
||||
|
||||
export interface EffectComposerPmndrsProps {
|
||||
enabled?: boolean
|
||||
depthBuffer?: boolean
|
||||
disableNormalPass?: boolean
|
||||
stencilBuffer?: boolean
|
||||
resolutionScale?: number
|
||||
autoClear?: boolean
|
||||
multisampling?: number
|
||||
frameBufferType?: number
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(defineProps<EffectComposerPmndrsProps>(), {
|
||||
enabled: true,
|
||||
autoClear: true,
|
||||
frameBufferType: HalfFloatType,
|
||||
disableNormalPass: false,
|
||||
depthBuffer: undefined,
|
||||
multisampling: 0,
|
||||
stencilBuffer: undefined,
|
||||
})
|
||||
const emit = defineEmits(['render'])
|
||||
|
||||
const { renderer } = useTresContext()
|
||||
const { scene, camera, sizes } = useTres()
|
||||
|
||||
const effectComposer: ShallowRef<EffectComposerImpl | null> = shallowRef(null)
|
||||
|
||||
let downSamplingPass: DepthDownsamplingPass | null = null
|
||||
let normalPass: NormalPass | null = null
|
||||
|
||||
provide(effectComposerInjectionKey, effectComposer)
|
||||
defineExpose({ composer: effectComposer })
|
||||
|
||||
function setNormalPass() {
|
||||
if (!effectComposer.value) {
|
||||
return
|
||||
}
|
||||
|
||||
normalPass = new NormalPass(scene.value, camera.value)
|
||||
normalPass.enabled = false
|
||||
effectComposer.value.addPass(normalPass)
|
||||
if (props.resolutionScale !== undefined && WEBGL.isWebGL2Available()) {
|
||||
downSamplingPass = new DepthDownsamplingPass({
|
||||
normalBuffer: normalPass.texture,
|
||||
resolutionScale: props.resolutionScale,
|
||||
})
|
||||
|
||||
downSamplingPass.enabled = false
|
||||
effectComposer.value.addPass(downSamplingPass)
|
||||
}
|
||||
}
|
||||
|
||||
const effectComposerParams = computed(() => {
|
||||
const plainEffectComposer = new EffectComposerImpl()
|
||||
const params = {
|
||||
depthBuffer: props.depthBuffer !== undefined
|
||||
? props.depthBuffer
|
||||
: plainEffectComposer.inputBuffer.depthBuffer,
|
||||
stencilBuffer:
|
||||
props.stencilBuffer !== undefined
|
||||
? props.stencilBuffer
|
||||
: plainEffectComposer.inputBuffer.stencilBuffer,
|
||||
multisampling: WEBGL.isWebGL2Available()
|
||||
? props.multisampling !== undefined
|
||||
? props.multisampling
|
||||
: plainEffectComposer.multisampling
|
||||
: 0,
|
||||
frameBufferType: props.frameBufferType !== undefined
|
||||
? props.frameBufferType
|
||||
: HalfFloatType,
|
||||
}
|
||||
|
||||
plainEffectComposer.dispose()
|
||||
|
||||
return params
|
||||
})
|
||||
|
||||
function initEffectComposer() {
|
||||
if (!renderer && !scene.value && !camera.value) {
|
||||
return
|
||||
}
|
||||
|
||||
effectComposer.value?.dispose()
|
||||
effectComposer.value = new EffectComposerImpl(renderer.instance as WebGLRenderer, effectComposerParams.value)
|
||||
effectComposer.value.addPass(new RenderPass(scene.value, camera.value))
|
||||
|
||||
if (!props.disableNormalPass) {
|
||||
setNormalPass()
|
||||
}
|
||||
}
|
||||
|
||||
watch([scene, camera, () => props.disableNormalPass], () => {
|
||||
if (!sizes.width.value || !sizes.height.value) {
|
||||
return
|
||||
}
|
||||
|
||||
initEffectComposer()
|
||||
})
|
||||
|
||||
watch(() => [sizes.width.value, sizes.height.value], ([width, height]) => {
|
||||
// effect composer should only live once the canvas has a size > 0
|
||||
if (!width && !height) {
|
||||
return
|
||||
}
|
||||
|
||||
if (effectComposer.value) {
|
||||
effectComposer.value.setSize(width, height)
|
||||
}
|
||||
else {
|
||||
initEffectComposer()
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
renderer.replaceRenderFunction((notifySuccess) => {
|
||||
if (props.enabled && renderer.instance && effectComposer.value && sizes.width.value && sizes.height.value) {
|
||||
const currentAutoClear = renderer.instance.autoClear
|
||||
renderer.instance.autoClear = props.autoClear
|
||||
if (props.stencilBuffer && !props.autoClear) {
|
||||
renderer.instance.clearStencil()
|
||||
}
|
||||
|
||||
effectComposer.value.render()
|
||||
emit('render', effectComposer.value)
|
||||
renderer.instance.autoClear = currentAutoClear
|
||||
notifySuccess()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
effectComposer.value?.dispose()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot />
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import type { BlendFunction } from 'postprocessing'
|
||||
|
||||
import { HueSaturationEffect } from 'postprocessing'
|
||||
|
||||
import { useEffectPmndrs } from '../../composables/use-effect-pmndrs'
|
||||
import { makePropWatchers } from '../../utils'
|
||||
|
||||
export interface HueSaturationPmndrsProps {
|
||||
/**
|
||||
* The saturation adjustment. A value of 0.0 results in grayscale, and 1.0 leaves saturation unchanged.
|
||||
* Range: [0.0, 1.0]
|
||||
*/
|
||||
saturation?: number
|
||||
|
||||
/**
|
||||
* The hue adjustment in radians.
|
||||
* Range: [-π, π] (or [0, 2π] for a full rotation)
|
||||
*/
|
||||
hue?: number
|
||||
|
||||
/**
|
||||
* The blend function. Defines how the effect blends with the original scene.
|
||||
*/
|
||||
blendFunction?: BlendFunction
|
||||
}
|
||||
|
||||
const props = defineProps<HueSaturationPmndrsProps>()
|
||||
|
||||
const { pass, effect } = useEffectPmndrs(() => new HueSaturationEffect(props), props)
|
||||
|
||||
defineExpose({ pass, effect })
|
||||
|
||||
makePropWatchers(
|
||||
[
|
||||
[() => props.blendFunction, 'blendMode.blendFunction'],
|
||||
[() => props.hue, 'hue'],
|
||||
[() => props.saturation, 'saturation'],
|
||||
],
|
||||
effect,
|
||||
() => new HueSaturationEffect(),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot />
|
||||
</template>
|
||||
@@ -1 +0,0 @@
|
||||
export { default as HueSaturationPmndrs } from './HueSaturationPmndrs.vue'
|
||||
@@ -1,2 +0,0 @@
|
||||
export { default as EffectComposerPmndrs } from './EffectComposerPmndrs.vue'
|
||||
export { HueSaturationPmndrs } from './effects'
|
||||
@@ -1 +0,0 @@
|
||||
export { useEffectPmndrs } from './use-effect-pmndrs'
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* https://github.com/Tresjs/post-processing/blob/c89b5b4353d889d58da4dd6746e64b32a3f711ec/src/core/pmndrs/EffectComposerPmndrs.vue
|
||||
*/
|
||||
|
||||
import type { Effect } from 'postprocessing'
|
||||
import type { Reactive, ShallowRef } from 'vue'
|
||||
|
||||
import { useTres } from '@tresjs/core'
|
||||
import { EffectPass } from 'postprocessing'
|
||||
import { inject, nextTick, onUnmounted, shallowRef, watch, watchEffect } from 'vue'
|
||||
|
||||
import { effectComposerInjectionKey } from '../components/EffectComposerPmndrs.vue'
|
||||
|
||||
/**
|
||||
* @param newEffectFunction - A function that returns a new effect instance.
|
||||
* @param passDependencies - A reactive object that the pass depends on (usually props). Changes to this object will trigger re-rendering.
|
||||
* @param dependencyFieldsTriggeringRecreation - fields in passDependencies that require effect recreation when changed
|
||||
*/
|
||||
export function useEffectPmndrs<T extends Effect, D extends Record<PropertyKey, any>>(newEffectFunction: () => T, passDependencies: Reactive<D>, dependencyFieldsTriggeringRecreation?: (keyof D)[]): {
|
||||
pass: ShallowRef<EffectPass | null>
|
||||
effect: ShallowRef<T | null>
|
||||
} {
|
||||
const composer = inject(effectComposerInjectionKey)
|
||||
|
||||
const pass = shallowRef<EffectPass | null>(null) as ShallowRef<EffectPass | null>
|
||||
const effect = shallowRef<T | null>(null) as ShallowRef<T | null>
|
||||
|
||||
const { scene, camera, invalidate } = useTres()
|
||||
|
||||
watch(passDependencies, () => invalidate())
|
||||
|
||||
const removePass = () => {
|
||||
if (pass.value) {
|
||||
composer?.value?.removePass(pass.value)
|
||||
}
|
||||
|
||||
effect.value?.dispose()
|
||||
pass.value?.dispose()
|
||||
}
|
||||
|
||||
const createEffect = (index?: number) => {
|
||||
if (!camera.value || !composer?.value || !scene.value) {
|
||||
return
|
||||
}
|
||||
|
||||
effect.value = newEffectFunction()
|
||||
pass.value = new EffectPass(camera.value, effect.value)
|
||||
|
||||
composer.value.addPass(pass.value, index)
|
||||
}
|
||||
|
||||
// Watch for changes in props that require effect recreation
|
||||
if (dependencyFieldsTriggeringRecreation) {
|
||||
watch(
|
||||
() => dependencyFieldsTriggeringRecreation.map(field => passDependencies[field]),
|
||||
() => {
|
||||
if (!composer?.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const index = composer.value?.passes.findIndex(p => p === pass.value)
|
||||
if (!~index) {
|
||||
return
|
||||
}
|
||||
|
||||
removePass()
|
||||
createEffect(index)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (!camera.value || !effect?.value) {
|
||||
return
|
||||
}
|
||||
|
||||
effect.value.mainCamera = camera.value
|
||||
})
|
||||
|
||||
// Initial effect creation
|
||||
const unwatch = watchEffect(() => {
|
||||
if (!camera.value || !composer?.value || !scene.value) {
|
||||
return
|
||||
}
|
||||
|
||||
nextTick(() => unwatch())
|
||||
if (effect.value) {
|
||||
return
|
||||
}
|
||||
|
||||
createEffect()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
removePass()
|
||||
})
|
||||
|
||||
return {
|
||||
pass,
|
||||
effect,
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
export {
|
||||
EffectComposerPmndrs,
|
||||
HueSaturationPmndrs,
|
||||
} from './components'
|
||||
export {
|
||||
useEffectPmndrs,
|
||||
} from './composables'
|
||||
export {
|
||||
get,
|
||||
makePropWatcher,
|
||||
makePropWatchers,
|
||||
makePropWatchersUsingAllProps,
|
||||
omit,
|
||||
set,
|
||||
} from './utils'
|
||||
@@ -1,2 +0,0 @@
|
||||
export { get, omit, set } from './object'
|
||||
export { makePropWatcher, makePropWatchers, makePropWatchersUsingAllProps } from './props'
|
||||
@@ -1,90 +0,0 @@
|
||||
const pathRegex = /([^[.\]])+/g
|
||||
|
||||
/**
|
||||
* Retrieves the value at a given path within a provided object.
|
||||
*
|
||||
* @template T - The type of value to be returned
|
||||
*
|
||||
* @param {any} obj - The object to extract value from
|
||||
* @param {string | string[]} path - A path or an array of path where the value should be get from
|
||||
*
|
||||
* @returns {T | undefined} - The value at the given path in the object, or undefined if path is not found
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* const obj = { a: { b: { c: 1 } } }
|
||||
*
|
||||
* const result = get(obj, 'a.b.c')
|
||||
*
|
||||
* console.log(result) // 1
|
||||
*/
|
||||
export function get<T>(obj: any, path: string | string[]): T | undefined {
|
||||
if (!path) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const pathArray = Array.isArray(path)
|
||||
? path
|
||||
: path.match(pathRegex)
|
||||
|
||||
return pathArray?.reduce((prevObj, key) => prevObj && prevObj[key], obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value at a given path within a provided object. If the path does not exist, nested objects will be created.
|
||||
*
|
||||
* @param {any} obj - The original object to set value in
|
||||
* @param {string | string[]} path - A path or an array of path where the value should be set
|
||||
* @param {any} value - The value to be set at the provided path
|
||||
*
|
||||
* @returns {void}
|
||||
*
|
||||
* @example
|
||||
* const obj = { a: { b: { c: 1 } } }
|
||||
*
|
||||
* set(obj, 'a.b.c', 2)
|
||||
*
|
||||
* console.log(obj) // { a: { b: { c: 2 } } }
|
||||
*/
|
||||
export function set(obj: any, path: string | string[], value: any): void {
|
||||
const pathArray = Array.isArray(path)
|
||||
? path
|
||||
: path.match(pathRegex)
|
||||
|
||||
if (pathArray) {
|
||||
pathArray.reduce((acc, key, i) => {
|
||||
if (acc[key] === undefined) {
|
||||
acc[key] = {}
|
||||
}
|
||||
if (i === pathArray.length - 1) {
|
||||
acc[key] = value
|
||||
}
|
||||
|
||||
return acc[key]
|
||||
}, obj)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Omits given properties from a provided object.
|
||||
*
|
||||
* @template T - An object with string keys and any type of values
|
||||
*
|
||||
* @param {T} obj - The original object to omit properties from
|
||||
* @param {(keyof T)[]} properties - An array of property key names to omit from the base object
|
||||
*
|
||||
* @returns {Partial<T>} The new object with omitted properties
|
||||
*
|
||||
* @example
|
||||
* const obj = { a: 1, b: 2, c: 3 }
|
||||
* const propsToOmit = ['b', 'c']
|
||||
*
|
||||
* const newObj = omit(obj, propsToOmit)
|
||||
*
|
||||
* console.log(newObj) // { a: 1 }
|
||||
*/
|
||||
export function omit<T extends Record<string, any>>(obj: T, properties: (keyof T)[]): Partial<T> {
|
||||
const newObj = { ...obj }
|
||||
properties.forEach(prop => delete newObj[prop])
|
||||
return newObj
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import type { Ref, WatchOptions } from 'vue'
|
||||
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { get, set } from './object'
|
||||
|
||||
/**
|
||||
* Creates a prop watcher function that monitors changes to a property and updates a target object.
|
||||
*
|
||||
* @template T - The type of the property being watched.
|
||||
* @template E - The type of the target object.
|
||||
* @param {() => T} propGetter - A function that retrieves the prop value to be watched.
|
||||
* @param {Ref<E>} target - A Ref representing the target object to be updated.
|
||||
* @param {string} propertyPath - The dot-separated path to the property within the target object.
|
||||
* @param {() => E & { dispose?(): void }} newPlainObjectFunction - A function that creates a new plain object to retrieve the defaults from with an optional "dispose" method for cleanup.
|
||||
* @param {WatchOptions} watchOptions - The options for watch.
|
||||
*/
|
||||
export function makePropWatcher<T, E>(
|
||||
propGetter: () => T,
|
||||
target: Ref<E>,
|
||||
propertyPath: string,
|
||||
newPlainObjectFunction: () => E & { dispose?: () => void },
|
||||
watchOptions: WatchOptions = {},
|
||||
) {
|
||||
return watch(propGetter, (newValue) => {
|
||||
if (!target.value) {
|
||||
return
|
||||
}
|
||||
if (newValue === undefined) {
|
||||
const plainObject = newPlainObjectFunction()
|
||||
|
||||
set(target.value, propertyPath, get(plainObject, propertyPath))
|
||||
|
||||
plainObject.dispose?.()
|
||||
}
|
||||
else {
|
||||
set(target.value, propertyPath, propGetter())
|
||||
}
|
||||
}, watchOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multiple prop watchers for monitoring changes to multiple properties and updating a target object.
|
||||
*
|
||||
* @template T - The type of the property being watched.
|
||||
* @template E - The type of the target object.
|
||||
* @param {(string | (() => T))[][]} propGettersAndPropertyPaths - An array of arrays containing pairs of prop getters and their corresponding property paths within the target object.
|
||||
* @param {Ref<E>} target - A Ref representing the target object to be updated.
|
||||
* @param {() => E & { dispose?(): void }} newPlainObjectFunction - A function that creates a new plain object to retrieve the defaults from with an optional "dispose" method for cleanup.
|
||||
*/
|
||||
export function makePropWatchers<E>(
|
||||
propGettersAndPropertyPaths: (string | (() => any))[][],
|
||||
target: Ref<E>,
|
||||
newPlainObjectFunction: () => E & { dispose?: () => void },
|
||||
) {
|
||||
return propGettersAndPropertyPaths.map(([propGetterFn, path]) => makePropWatcher(
|
||||
propGetterFn as () => any,
|
||||
target,
|
||||
path as string,
|
||||
newPlainObjectFunction,
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multiple prop watchers via the props object for monitoring changes to multiple properties and updating a target object.
|
||||
* Use this method in case the prop names match the names of the properties you want to set on your target object.
|
||||
*
|
||||
* @param props - The props object. Usually created via defineProps.
|
||||
* @param {Ref<E>} target - A Ref representing the target object to be updated.
|
||||
* @param {() => E & { dispose?(): void }} newPlainObjectFunction - A function that creates a new plain object to retrieve the defaults from with an optional "dispose" method for cleanup.
|
||||
*/
|
||||
export function makePropWatchersUsingAllProps<E>(
|
||||
props: { [key: PropertyKey]: any },
|
||||
target: Ref<E>,
|
||||
newPlainObjectFunction: () => E & { dispose?: () => void },
|
||||
) {
|
||||
return Object.keys(props).map(key => makePropWatcher(
|
||||
() => props[key],
|
||||
target,
|
||||
key,
|
||||
newPlainObjectFunction,
|
||||
))
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"jsx": "preserve",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ESNext"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"types": [
|
||||
"vitest",
|
||||
"vite/client"
|
||||
],
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"plugins": [
|
||||
"@vue-macros/volar/define-models",
|
||||
"@vue-macros/volar/define-slots"
|
||||
],
|
||||
"skipTemplateCodegen": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Generated
+3
-106
@@ -314,9 +314,6 @@ importers:
|
||||
'@proj-airi/ui':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/ui
|
||||
'@ricky0123/vad-web':
|
||||
specifier: ^0.0.29
|
||||
version: 0.0.29
|
||||
'@stdlib/string-base-kebabcase':
|
||||
specifier: ^0.2.2
|
||||
version: 0.2.2
|
||||
@@ -714,9 +711,6 @@ importers:
|
||||
'@proj-airi/ui-transitions':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/ui-transitions
|
||||
'@ricky0123/vad-web':
|
||||
specifier: ^0.0.29
|
||||
version: 0.0.29
|
||||
'@standard-schema/spec':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
@@ -1448,15 +1442,6 @@ importers:
|
||||
'@shikijs/rehype':
|
||||
specifier: ^3.15.0
|
||||
version: 3.15.0
|
||||
'@tresjs/cientos':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3)))(@types/three@0.181.0)(react@18.3.1)(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@tresjs/core':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@tresjs/post-processing':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3)))(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@vueuse/core':
|
||||
specifier: ^14.0.0
|
||||
version: 14.0.0(vue@3.5.24(typescript@5.9.3))
|
||||
@@ -1734,15 +1719,15 @@ importers:
|
||||
'@proj-airi/stage-shared':
|
||||
specifier: workspace:*
|
||||
version: link:../stage-shared
|
||||
'@proj-airi/tresjs':
|
||||
specifier: workspace:*
|
||||
version: link:../tresjs
|
||||
'@tresjs/cientos':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3)))(@types/three@0.181.0)(react@18.3.1)(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@tresjs/core':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@tresjs/post-processing':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3)))(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
'@vueuse/core':
|
||||
specifier: ^14.0.0
|
||||
version: 14.0.0(vue@3.5.24(typescript@5.9.3))
|
||||
@@ -1785,31 +1770,6 @@ importers:
|
||||
specifier: ^2.20.1
|
||||
version: 2.20.1(typescript@5.9.3)
|
||||
|
||||
packages/tresjs:
|
||||
dependencies:
|
||||
'@tresjs/cientos':
|
||||
specifier: '>=5.0.0 <6.0.0'
|
||||
version: 5.1.0(@tresjs/core@5.1.0(three@0.180.0)(vue@3.5.24(typescript@5.9.3)))(@types/three@0.181.0)(react@18.3.1)(three@0.180.0)(vue@3.5.24(typescript@5.9.3))
|
||||
'@tresjs/core':
|
||||
specifier: '>=5.0.0 <6.0.0'
|
||||
version: 5.1.0(three@0.180.0)(vue@3.5.24(typescript@5.9.3))
|
||||
postprocessing:
|
||||
specifier: '>=6.0.0 <7.0.0'
|
||||
version: 6.38.0(three@0.180.0)
|
||||
three:
|
||||
specifier: '>=0.180.0 <0.181.0'
|
||||
version: 0.180.0
|
||||
vue:
|
||||
specifier: '>=3.5.0 <4.0.0'
|
||||
version: 3.5.24(typescript@5.9.3)
|
||||
devDependencies:
|
||||
'@types/three':
|
||||
specifier: ^0.181.0
|
||||
version: 0.181.0
|
||||
vue-tsc:
|
||||
specifier: ^3.1.4
|
||||
version: 3.1.4(typescript@5.9.3)
|
||||
|
||||
packages/ui:
|
||||
dependencies:
|
||||
'@vueuse/core':
|
||||
@@ -14665,9 +14625,6 @@ packages:
|
||||
three@0.128.0:
|
||||
resolution: {integrity: sha512-i0ap/E+OaSfzw7bD1TtYnPo3VEplkl70WX5fZqZnfZsE3k3aSFudqrrC9ldFZfYFkn1zwDmBcdGfiIm/hnbyZA==}
|
||||
|
||||
three@0.180.0:
|
||||
resolution: {integrity: sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w==}
|
||||
|
||||
three@0.181.1:
|
||||
resolution: {integrity: sha512-bz9xZUQMw3pJbjKy7roiwXWgAp+oVUa+4k5o0oBAQ+IFJuru1xzvtk63h6k72XZanXS/SgoEhV6927Vgazyq2w==}
|
||||
|
||||
@@ -21472,22 +21429,6 @@ snapshots:
|
||||
'@tootallnate/quickjs-emscripten@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@tresjs/cientos@5.1.0(@tresjs/core@5.1.0(three@0.180.0)(vue@3.5.24(typescript@5.9.3)))(@types/three@0.181.0)(react@18.3.1)(three@0.180.0)(vue@3.5.24(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@tresjs/core': 5.1.0(three@0.180.0)(vue@3.5.24(typescript@5.9.3))
|
||||
'@vueuse/core': 13.9.0(vue@3.5.24(typescript@5.9.3))
|
||||
camera-controls: 2.9.0(three@0.180.0)
|
||||
stats-gl: 2.4.2(@types/three@0.181.0)(three@0.180.0)
|
||||
stats.js: 0.17.0
|
||||
three: 0.180.0
|
||||
three-custom-shader-material: 5.4.0(react@18.3.1)(three@0.180.0)
|
||||
three-stdlib: 2.36.0(three@0.180.0)
|
||||
vue: 3.5.24(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- '@react-three/fiber'
|
||||
- '@types/three'
|
||||
- react
|
||||
|
||||
'@tresjs/cientos@5.1.0(@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3)))(@types/three@0.181.0)(react@18.3.1)(three@0.181.1)(vue@3.5.24(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@tresjs/core': 5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3))
|
||||
@@ -21504,15 +21445,6 @@ snapshots:
|
||||
- '@types/three'
|
||||
- react
|
||||
|
||||
'@tresjs/core@5.1.0(three@0.180.0)(vue@3.5.24(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@pmndrs/pointer-events': 6.6.26
|
||||
'@vue/devtools-api': 7.7.7
|
||||
'@vueuse/core': 13.9.0(vue@3.5.24(typescript@5.9.3))
|
||||
radashi: 12.6.2
|
||||
three: 0.180.0
|
||||
vue: 3.5.24(typescript@5.9.3)
|
||||
|
||||
'@tresjs/core@5.1.0(three@0.181.1)(vue@3.5.24(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@pmndrs/pointer-events': 6.6.26
|
||||
@@ -24429,10 +24361,6 @@ snapshots:
|
||||
|
||||
camelcase@8.0.0: {}
|
||||
|
||||
camera-controls@2.9.0(three@0.180.0):
|
||||
dependencies:
|
||||
three: 0.180.0
|
||||
|
||||
camera-controls@2.9.0(three@0.181.1):
|
||||
dependencies:
|
||||
three: 0.181.1
|
||||
@@ -30634,10 +30562,6 @@ snapshots:
|
||||
|
||||
postgres@3.4.7: {}
|
||||
|
||||
postprocessing@6.38.0(three@0.180.0):
|
||||
dependencies:
|
||||
three: 0.180.0
|
||||
|
||||
postprocessing@6.38.0(three@0.181.1):
|
||||
dependencies:
|
||||
three: 0.181.1
|
||||
@@ -31990,11 +31914,6 @@ snapshots:
|
||||
|
||||
stat-mode@1.0.0: {}
|
||||
|
||||
stats-gl@2.4.2(@types/three@0.181.0)(three@0.180.0):
|
||||
dependencies:
|
||||
'@types/three': 0.181.0
|
||||
three: 0.180.0
|
||||
|
||||
stats-gl@2.4.2(@types/three@0.181.0)(three@0.181.1):
|
||||
dependencies:
|
||||
'@types/three': 0.181.0
|
||||
@@ -32322,16 +32241,6 @@ snapshots:
|
||||
dependencies:
|
||||
real-require: 0.2.0
|
||||
|
||||
three-custom-shader-material@5.4.0(react@18.3.1)(three@0.180.0):
|
||||
dependencies:
|
||||
glsl-token-functions: 1.0.1
|
||||
glsl-token-string: 1.0.1
|
||||
glsl-tokenizer: 2.1.5
|
||||
object-hash: 3.0.0
|
||||
three: 0.180.0
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
|
||||
three-custom-shader-material@5.4.0(react@18.3.1)(three@0.181.1):
|
||||
dependencies:
|
||||
glsl-token-functions: 1.0.1
|
||||
@@ -32342,16 +32251,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
|
||||
three-stdlib@2.36.0(three@0.180.0):
|
||||
dependencies:
|
||||
'@types/draco3d': 1.4.10
|
||||
'@types/offscreencanvas': 2019.7.3
|
||||
'@types/webxr': 0.5.20
|
||||
draco3d: 1.5.7
|
||||
fflate: 0.6.10
|
||||
potpack: 1.0.2
|
||||
three: 0.180.0
|
||||
|
||||
three-stdlib@2.36.0(three@0.181.1):
|
||||
dependencies:
|
||||
'@types/draco3d': 1.4.10
|
||||
@@ -32366,8 +32265,6 @@ snapshots:
|
||||
|
||||
three@0.128.0: {}
|
||||
|
||||
three@0.180.0: {}
|
||||
|
||||
three@0.181.1: {}
|
||||
|
||||
through2@0.6.5:
|
||||
|
||||
Reference in New Issue
Block a user