Skip to content

Commit

Permalink
feat: pass all provides down to custom renderer (#806)
Browse files Browse the repository at this point in the history
* feat: pass all provides down to custom renderer

* chore: eslint auto import

* fix: solve precedence issue and added dedicated playground

* chore: disable eslint console rule in playground

* feat: provide inject reactivity seems to work now

* chore: remove unsued import

* feature: just removed console log after testing in another package

* feat: opt-out flag for disabling provide bridge

* feat: correct the precedence of provide keys

* chore: fix lint

* feat: changed flag to positive

* docs: correct back the docs
  • Loading branch information
alvarosabu authored Sep 30, 2024
1 parent fd3b599 commit b4a3866
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/api/tres-canvas.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ renderer.shadowMap.type = PCFSoftShadowMap
| **toneMappingExposure** | Exposure level of tone mapping. | `1` |
| **useLegacyLights** | Whether to use the legacy lighting mode or not | `true` |
| **windowSize** | Whether to use the window size as the canvas size or the parent element. | `false` |
| **enableProvideBridge** | Enables the provide/inject bridge between Vue context and TresCanvas. | `true` |

### Defaults

Expand Down
67 changes: 67 additions & 0 deletions playground/.eslintrc-auto-import.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useSlots": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true
}
}
1 change: 1 addition & 0 deletions playground/vue/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ declare module 'vue' {
Overlay: typeof import('./src/components/Overlay.vue')['default']
OverlayInfo: typeof import('./src/components/OverlayInfo.vue')['default']
PbrSphere: typeof import('./src/components/PbrSphere.vue')['default']
ProvideBridge: typeof import('./src/components/ProvideBridge.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TakeOverLoopExperience: typeof import('./src/components/TakeOverLoopExperience.vue')['default']
Expand Down
4 changes: 4 additions & 0 deletions playground/vue/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ function setBodyClass(routeName: string) {
document.body.className = routeName
}
watch([route], () => setBodyClass(route.name?.toString() ?? ''))
provide('v-route', route)
provide('useTres', {
message: `Im not the real useTres, but I can provide you with some data!`,
})
</script>

<template>
Expand Down
20 changes: 20 additions & 0 deletions playground/vue/src/components/ProvideBridge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!-- ProvideBridge.vue -->
<script setup lang="ts">
import { provide } from 'vue'

interface Props {
keysValues: Record<string, any>
}
const props = withDefaults(defineProps<Props>(), {
keysValues: () => ({}),
})
for (const [key, value] of Object.entries(props.keysValues)) {
provide(key, value)
}
</script>

<template>
<TresGroup>
<slot></slot>
</TresGroup>
</template>
2 changes: 1 addition & 1 deletion playground/vue/src/pages/basic/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const toonTealMaterial = new MeshToonMaterial({
v-bind="state"
>
<TresPerspectiveCamera
:position="[0, 8, 8]"
:position="{ x: 0, y: 8, z: 8 }"
:fov="45"
:near="0.1"
:far="1000"
Expand Down
15 changes: 15 additions & 0 deletions playground/vue/src/pages/issues/732/ProvideInjectExperience.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import SubComponentWithInject from './SubComponentWithInject.vue'
provide('test', '✅ Precedence is correct')
</script>

<template>
<TresCanvas clear-color="#82DBC5">
<TresPerspectiveCamera :position="[11, 11, 11]" :look-at="[0, 0, 0]" />
<SubComponentWithInject />
<TresGridHelper />
<TresAmbientLight :intensity="1" />
</TresCanvas>
</template>
24 changes: 24 additions & 0 deletions playground/vue/src/pages/issues/732/SubComponentWithInject.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- eslint-disable no-console -->
<script setup lang="ts">
import { inject, watchEffect } from 'vue'

const awiwi = inject('awiwi')
const bululu = inject('bululu')
const vRoute = inject('v-route')
console.log(inject('test'))

watchEffect(() => console.log('tres:awiwi', awiwi?.a))

watchEffect(() => console.log('tres:bululu', bululu?.value))

watchEffect(() => console.log('tres:v-route', vRoute))

watchEffect(() => console.log('tres:useTres', inject('useTres')))
</script>

<template>
<TresMesh>
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshNormalMaterial />
</TresMesh>
</template>
20 changes: 20 additions & 0 deletions playground/vue/src/pages/issues/732/SubVueComponentWithInject.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import { inject, watchEffect } from 'vue'
const awiwi = inject('awiwi')
const bululu = inject('bululu')
// eslint-disable-next-line no-console
watchEffect(() => console.log('vue:awiwi', awiwi?.a))
// eslint-disable-next-line no-console
watchEffect(() => console.log('vue:bululu', bululu?.value))
// eslint-disable-next-line no-console
watchEffect(() => console.log('vue:v-route', inject('v-route')))
// eslint-disable-next-line no-console
watchEffect(() => console.log('vue:useTres', inject('useTres')))
</script>

<template>
<p>awiwi: {{ awiwi }}</p>
<p>bululu: {{ bululu }}</p>
<p>v-route: {{ inject('v-route') }}</p>
</template>
24 changes: 24 additions & 0 deletions playground/vue/src/pages/issues/732/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import { provide, reactive } from 'vue'
import ProvideInjectExperience from './ProvideInjectExperience.vue'
import SubVueComponentWithInject from './SubVueComponentWithInject.vue'
const obj = reactive({
a: 1,
})
const bululu = ref(1)
provide('awiwi', obj)
provide('bululu', bululu)
provide('test', '❌ Precendence is incorrect')
function onClick() {
obj.a++
bululu.value++
}
</script>

<template>
<button @click="onClick">Click me </button>
<SubVueComponentWithInject />
<ProvideInjectExperience />
</template>
6 changes: 5 additions & 1 deletion playground/vue/src/router/routes/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@ export const issuesRoutes = [
name: '#796: unmounted',
component: () => import('../../pages/issues/796/index.vue'),
},

{
path: '/issues/732',
name: '#732: provide/inject',
component: () => import('../../pages/issues/732/index.vue'),
},
]
34 changes: 32 additions & 2 deletions src/components/TresCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export interface TresCanvasProps
camera?: TresCamera
preset?: RendererPresetsType
windowSize?: boolean
// Misc opt-out flags
enableProvideBridge?: boolean
}
const props = withDefaults(defineProps<TresCanvasProps>(), {
Expand All @@ -68,6 +71,7 @@ const props = withDefaults(defineProps<TresCanvasProps>(), {
logarithmicDepthBuffer: undefined,
failIfMajorPerformanceCaveat: undefined,
renderMode: 'always',
enableProvideBridge: true,
})
// Define emits for Pointer events, pass `emit` into useTresEventManager so we can emit events off of TresCanvas
Expand Down Expand Up @@ -104,14 +108,40 @@ const canvas = ref<HTMLCanvasElement>()
*/
const scene = shallowRef<TresScene | Scene>(new Scene())
const instance = getCurrentInstance()?.appContext.app
const instance = getCurrentInstance()
extend(THREE)
const createInternalComponent = (context: TresContext, empty = false) =>
defineComponent({
setup() {
const ctx = getCurrentInstance()?.appContext
if (ctx) { ctx.app = instance as App }
if (ctx) { ctx.app = instance?.appContext.app as App }
const provides = {}
// Helper function to recursively merge provides from parents
function mergeProvides(currentInstance: any) {
if (!currentInstance) { return }
// Recursively process the parent instance
if (currentInstance.parent) {
mergeProvides(currentInstance.parent)
}
// Extract provides from the current instance and merge them
if (currentInstance.provides) {
Object.assign(provides, currentInstance.provides)
}
}
// Start the recursion from the initial instance
if (instance?.parent && props.enableProvideBridge) {
mergeProvides(instance.parent)
Object.entries(provides)
.forEach(([key, value]) => {
provide(key, value)
})
}
provide('useTres', context)
provide('extend', extend)
Expand Down

0 comments on commit b4a3866

Please sign in to comment.