Skip to content

Commit 10399b3

Browse files
committed
1 parent 30ffb95 commit 10399b3

4 files changed

Lines changed: 90 additions & 61 deletions

File tree

.claude/settings.local.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"WebFetch(domain:docs.solidjs.com)"
5+
],
6+
"deny": []
7+
}
8+
}

src/props.ts

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { isEventType } from "./create-events.ts"
2323
import { useThree } from "./hooks.ts"
2424
import { addToEventListeners, useCanvasProps } from "./internal-context.ts"
2525
import type { Instance } from "./types.ts"
26-
import { when } from "./utils/conditionals.ts"
26+
import { check } from "./utils/conditionals.ts"
2727
import { hasColorSpace } from "./utils/has-colorspace.ts"
2828
import { isInstance } from "./utils/is-instance.ts"
2929
import { resolve } from "./utils/resolve.ts"
@@ -44,7 +44,7 @@ import { resolve } from "./utils/resolve.ts"
4444
* @param props - An object containing the props to apply. This includes both direct properties
4545
* and special properties like `ref` and `children`.
4646
*/
47-
export function manageProps<T>(object: Accessor<Instance<T>>, props: any) {
47+
export function manageProps<T extends object>(object: Accessor<T>, props: any) {
4848
const [local, instanceProps] = splitProps(props, ["ref", "args", "object", "attach", "children"])
4949

5050
// Assign ref
@@ -53,12 +53,14 @@ export function manageProps<T>(object: Accessor<Instance<T>>, props: any) {
5353
else local.ref = object()
5454
})
5555

56-
// Connect or attach children to THREE-instance
57-
const childrenAccessor = children(() => props.children)
58-
createRenderEffect(() =>
59-
// @ts-expect-error TODO: fix type-error
60-
manageSceneGraph(object(), childrenAccessor as unknown as Accessor<Instance>),
61-
)
56+
createRenderEffect(() => {
57+
if ("children" in props) {
58+
// Connect or attach children to THREE-instance
59+
const childrenAccessor = children(() => props.children)
60+
// @ts-expect-error TODO: fix type-error
61+
manageSceneGraph(object(), childrenAccessor as unknown as Accessor<Instance>)
62+
}
63+
})
6264

6365
// Apply the props to THREE-instance
6466
createRenderEffect(() => {
@@ -69,7 +71,7 @@ export function manageProps<T>(object: Accessor<Instance<T>>, props: any) {
6971

7072
// Automatically dispose
7173
onCleanup(() =>
72-
when(object, object => {
74+
check(object, object => {
7375
if ("dispose" in object && typeof object.dispose === "function") {
7476
object.dispose()
7577
}
@@ -83,20 +85,22 @@ export function manageProps<T>(object: Accessor<Instance<T>>, props: any) {
8385
/* */
8486
/**********************************************************************************/
8587

86-
export function applyProps<T>(object: Instance<T>, props: any) {
87-
const keys = Object.keys(props)
88-
for (const key of keys) {
89-
// An array of sub-property-keys:
90-
// p.ex in <T.Mesh position={} position-x={}/> position's subKeys will be ['position-x']
91-
const subKeys = keys.filter(_key => key !== _key && _key.includes(key))
92-
createRenderEffect(() => {
93-
applyProp(object, key, props[key])
94-
// If property updates, apply its sub-properties immediately after.
95-
for (const subKey of subKeys) {
96-
applyProp(object, subKey, props[subKey])
97-
}
98-
})
99-
}
88+
export function applyProps<T>(object: T, props: any) {
89+
createRenderEffect(() => {
90+
const keys = Object.keys(props)
91+
for (const key of keys) {
92+
// An array of sub-property-keys:
93+
// p.ex in <T.Mesh position={} position-x={}/> position's subKeys will be ['position-x']
94+
const subKeys = keys.filter(_key => key !== _key && _key.includes(key))
95+
createRenderEffect(() => {
96+
applyProp(object, key, props[key])
97+
// If property updates, apply its sub-properties immediately after.
98+
for (const subKey of subKeys) {
99+
applyProp(object, subKey, props[subKey])
100+
}
101+
})
102+
}
103+
})
100104
}
101105

102106
/**********************************************************************************/
@@ -127,7 +131,7 @@ const NEEDS_UPDATE = [
127131
* @param type - The property name, which can include nested paths indicated by hyphens.
128132
* @param value - The value to be assigned to the property; can be of any appropriate type.
129133
*/
130-
export function applyProp<T>(source: Instance<T>, type: string, value: any) {
134+
export function applyProp<T>(source: T, type: string, value: any) {
131135
if (!source) {
132136
console.error("error while applying prop", source, type, value)
133137
return
@@ -140,7 +144,7 @@ export function applyProp<T>(source: Instance<T>, type: string, value: any) {
140144
if (type.indexOf("-") > -1) {
141145
const [property, ...rest] = type.split("-")
142146
// @ts-expect-error TODO: fix type-error
143-
applyProp(source[property as string], rest.join("-"), value)
147+
applyProp(source[property], rest.join("-"), value)
144148
return
145149
}
146150

src/utils/conditionals.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { Accessor, Resource } from "solid-js"
1+
import { type Accessor, createEffect, createMemo } from "solid-js"
22

3-
export function when<
3+
export function check<
44
T,
55
const TAccessor extends Accessor<T> | T,
66
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -9,7 +9,7 @@ export function when<
99
const TResult,
1010
>(accessor: TAccessor, callback: (value: TValues) => TResult): TResult | undefined
1111

12-
export function when<
12+
export function check<
1313
T,
1414
const TAccessor extends Accessor<T> | T,
1515
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -20,10 +20,10 @@ export function when<
2020
>(
2121
accessor: TAccessor,
2222
callback: (value: TValues) => TResult,
23-
fallback: () => TFallbackResult,
23+
fallback?: () => TFallbackResult,
2424
): TResult | TFallbackResult
2525

26-
export function when<
26+
export function check<
2727
T,
2828
const TAccessor extends Accessor<T> | T,
2929
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -47,7 +47,7 @@ export function when<
4747
* @param callback The callback function to be executed if the accessor's value is truthy.
4848
* @returns A function that can be called to execute the callback conditionally based on the accessor's value.
4949
*/
50-
export function whenever<
50+
export function when<
5151
T,
5252
const TAccessor extends Accessor<T> | T,
5353
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -56,7 +56,7 @@ export function whenever<
5656
const TResult,
5757
>(accessor: TAccessor, callback: (value: TValues) => TResult): () => TResult | undefined
5858

59-
export function whenever<
59+
export function when<
6060
const T,
6161
const TAccessor extends Accessor<T> | T,
6262
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -70,7 +70,7 @@ export function whenever<
7070
fallback: () => TFallbackResult,
7171
): () => TResult | TFallbackResult
7272

73-
export function whenever<
73+
export function when<
7474
T,
7575
const TAccessor extends Accessor<T> | T,
7676
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
@@ -83,8 +83,7 @@ export function whenever<
8383
callback: (value: TValues) => TResult,
8484
fallback?: () => TFallbackResult,
8585
): () => TResult | TFallbackResult | undefined {
86-
// @ts-expect-error
87-
return () => when(accessor, callback, fallback)
86+
return () => check(accessor, callback, fallback)
8887
}
8988

9089
/**
@@ -121,3 +120,25 @@ export function wrapNullableResource<T extends Resource<any>>(
121120
): Accessor<false | [ReturnType<T>]> {
122121
return () => value.state === "ready" && [value()]
123122
}
123+
124+
export function whenEffect<
125+
T,
126+
const TAccessor extends Accessor<T> | T,
127+
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
128+
? Exclude<ReturnType<Exclude<TAccessor, undefined>>, null | undefined | false>
129+
: Exclude<TAccessor, null | undefined | false>,
130+
const TResult,
131+
>(accessor: TAccessor, callback: (value: TValues) => TResult) {
132+
createEffect(when(accessor, callback))
133+
}
134+
135+
export function whenMemo<
136+
T,
137+
const TAccessor extends Accessor<T> | T,
138+
const TValues extends TAccessor extends ((...args: any[]) => any) | undefined
139+
? Exclude<ReturnType<Exclude<TAccessor, undefined>>, null | undefined | false>
140+
: Exclude<TAccessor, null | undefined | false>,
141+
const TResult,
142+
>(accessor: TAccessor, callback: (value: TValues) => TResult) {
143+
return createMemo(when(accessor, callback))
144+
}

src/utils/use-measure.ts

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createEffect, createMemo, createSignal, mergeProps, onCleanup } from "solid-js"
2-
import { whenever } from "./conditionals.ts"
2+
import { when, whenEffect } from "./conditionals.ts"
33
import { debounce as createDebounce } from "./debounce.ts"
44

55
declare type ResizeObserverCallback = (entries: any[], observer: ResizeObserver) => void
@@ -77,7 +77,7 @@ export function useMeasure(options?: UseMeasureOptions) {
7777
return forceRefresh
7878
}
7979

80-
const forceRefresh = whenever(element, element => {
80+
const forceRefresh = when(element, element => {
8181
const { left, top, width, height, bottom, right, x, y } =
8282
element.getBoundingClientRect() as unknown as Measure
8383

@@ -114,24 +114,22 @@ export function useMeasure(options?: UseMeasureOptions) {
114114
onCleanup(() => globalThis.removeEventListener("scroll", onScroll, true))
115115
})
116116

117-
createEffect(
118-
whenever(scrollContainers, scrollContainers => {
119-
if (!config.scroll) return
120-
121-
scrollContainers.forEach(scrollContainer =>
122-
scrollContainer.addEventListener("scroll", onScroll, {
123-
capture: true,
124-
passive: true,
125-
}),
126-
)
127-
128-
onCleanup(() => {
129-
scrollContainers.forEach(element => {
130-
element.removeEventListener("scroll", onScroll, true)
131-
})
117+
whenEffect(scrollContainers, scrollContainers => {
118+
if (!config.scroll) return
119+
120+
scrollContainers.forEach(scrollContainer =>
121+
scrollContainer.addEventListener("scroll", onScroll, {
122+
capture: true,
123+
passive: true,
124+
}),
125+
)
126+
127+
onCleanup(() => {
128+
scrollContainers.forEach(element => {
129+
element.removeEventListener("scroll", onScroll, true)
132130
})
133-
}),
134-
)
131+
})
132+
})
135133
})
136134

137135
createEffect(() => {
@@ -140,13 +138,11 @@ export function useMeasure(options?: UseMeasureOptions) {
140138
globalThis.addEventListener("resize", onResize)
141139
onCleanup(() => globalThis.removeEventListener("resize", onResize))
142140

143-
createEffect(
144-
whenever(element, element => {
145-
const observer = new ResizeObserver(onResize)
146-
observer.observe(element)
147-
onCleanup(() => observer.disconnect())
148-
}),
149-
)
141+
whenEffect(element, element => {
142+
const observer = new ResizeObserver(onResize)
143+
observer.observe(element)
144+
onCleanup(() => observer.disconnect())
145+
})
150146
})
151147

152148
return {

0 commit comments

Comments
 (0)