@@ -114,7 +114,7 @@ export interface Viewport {
114114 aspect : number
115115}
116116
117- /** Possible camera types . */
117+ /** Possible camera kinds . */
118118export type CameraKind = PerspectiveCamera | OrthographicCamera
119119
120120export type Loader < TSource , TResult extends object > = {
@@ -196,7 +196,7 @@ export type Props<T, TPlugins extends Plugin[] | undefined = Plugin[]> = Partial
196196 raycastable : boolean
197197 plugins : TPlugins
198198 } ,
199- TPlugins extends Plugin [ ] ? PluginPropsOf < InstanceOf < T > , TPlugins > : { } ,
199+ TPlugins extends Plugin [ ] ? InferPluginProps < InstanceOf < T > , TPlugins > : { } ,
200200 ]
201201 >
202202>
@@ -306,145 +306,147 @@ export interface Plugin<TFn = (element: any) => any> {
306306 ( context : Context ) : TFn
307307}
308308
309+ /**
310+ * Plugin function interface that defines all possible plugin creation patterns.
311+ *
312+ * Plugins extend solid-three components with additional functionality and can be:
313+ * - Global: apply to all elements
314+ * - Filtered: apply only to specific element types (via constructor array or type guard)
315+ * - With setup: access to the Three.js context during initialization
316+ *
317+ * @example
318+ * // Global plugin
319+ * const LogPlugin = plugin(element => ({
320+ * log: (message: string) => console.log(`[${element.type}] ${message}`)
321+ * }))
322+ *
323+ * @example
324+ * // Filtered plugin with constructor array
325+ * const ShakePlugin = plugin([THREE.Camera, THREE.Mesh], element => ({
326+ * shake: (intensity = 0.1) => {
327+ * useFrame(() => {
328+ * element.position.x += (Math.random() - 0.5) * intensity
329+ * })
330+ * }
331+ * }))
332+ *
333+ * @example
334+ * // Filtered plugin with type guard
335+ * const MaterialPlugin = plugin(
336+ * (element): element is THREE.Mesh => element instanceof THREE.Mesh,
337+ * element => ({
338+ * setColor: (color: string) => element.material.color.set(color)
339+ * })
340+ * )
341+ *
342+ * @example
343+ * // Plugin with setup context
344+ * const ContextPlugin = plugin
345+ * .setup((context) => ({ scene: context.scene }))
346+ * .then([THREE.Object3D], (element, context) => ({
347+ * addToScene: () => context.scene.add(element)
348+ * }))
349+ */
309350export interface PluginFn {
310- // No setup - direct usage with one argument (global)
311- < Methods extends Record < string , any > > ( methods : ( element : any ) => Methods ) : Plugin <
351+ /**
352+ * Creates a global plugin that applies to all elements.
353+ *
354+ * @param methods - Function that receives an element and returns plugin methods
355+ * @returns Plugin that applies to all elements
356+ */
357+ < const Methods extends Record < string , any > > ( methods : ( element : any ) => Methods ) : Plugin <
312358 ( element : any ) => Methods
313359 >
314360
315- // No setup - direct usage with two arguments (array of constructors)
316- < T extends readonly Constructor [ ] , Methods extends Record < string , any > > (
361+ /**
362+ * Creates a filtered plugin that applies only to specific constructor types.
363+ *
364+ * @param Constructors - Array of constructor functions to filter by
365+ * @param methods - Function that receives a filtered element and returns plugin methods
366+ * @returns Plugin that applies only to matching constructor types
367+ */
368+ < const T extends readonly Constructor [ ] , const Methods extends Record < string , any > > (
317369 Constructors : T ,
318370 methods : ( element : T extends readonly Constructor < infer U > [ ] ? U : never ) => Methods ,
319371 ) : Plugin < {
320372 ( element : T extends readonly Constructor < infer U > [ ] ? U : never ) : Methods
321- ( element : any ) : { }
322373 } >
323374
324- // No setup - direct usage with two arguments (type guard)
325- < T , Methods extends Record < string , any > > (
375+ /**
376+ * Creates a filtered plugin that applies only to elements matching a type guard.
377+ *
378+ * @param condition - Type guard function that determines if plugin applies
379+ * @param methods - Function that receives a filtered element and returns plugin methods
380+ * @returns Plugin that applies only to elements matching the type guard
381+ */
382+ < const T , const Methods extends Record < string , any > > (
326383 condition : ( element : unknown ) => element is T ,
327384 methods : ( element : T ) => Methods ,
328385 ) : Plugin < {
329386 ( element : T ) : Methods
330- ( element : any ) : { }
331387 } >
332388
333- // Setup function
334- setup < TSetupContext extends object > (
389+ /**
390+ * Creates a plugin with access to setup context.
391+ *
392+ * The setup function runs once when the plugin is initialized and receives
393+ * the Three.js context. The returned data is passed to all plugin methods.
394+ *
395+ * @param setupFn - Function that receives the Three.js context and returns setup data
396+ * @returns Object with 'then' method to define the plugin behavior
397+ */
398+ setup < const TSetupContext extends object > (
335399 setupFn : ( context : Context ) => TSetupContext ,
336400 ) : {
337401 then : {
338- // With setup - one argument (global)
339- < Methods extends Record < string , any > > (
402+ /**
403+ * Creates a global plugin with setup context.
404+ *
405+ * @param methods - Function that receives element and setup context, returns plugin methods
406+ * @returns Plugin that applies to all elements with setup context
407+ */
408+ < const Methods extends Record < string , any > > (
340409 methods : ( element : any , context : TSetupContext ) => Methods ,
341410 ) : Plugin < ( element : any ) => Methods >
342411
343- // With setup - two arguments (array of constructors)
344- < T extends readonly Constructor [ ] , Methods extends Record < string , any > > (
412+ /**
413+ * Creates a filtered plugin with setup context using constructor array.
414+ *
415+ * @param Constructors - Array of constructor functions to filter by
416+ * @param methods - Function that receives filtered element and setup context, returns plugin methods
417+ * @returns Plugin that applies only to matching constructor types with setup context
418+ */
419+ < const T extends readonly Constructor [ ] , const Methods extends Record < string , any > > (
345420 Constructors : T ,
346421 methods : (
347422 element : T extends readonly Constructor < infer U > [ ] ? U : never ,
348423 context : TSetupContext ,
349424 ) => Methods ,
350425 ) : Plugin < {
351426 ( element : T extends readonly Constructor < infer U > [ ] ? U : never ) : Methods
352- ( element : any ) : { }
353427 } >
354428
355- // With setup - two arguments (type guard)
356- < T , Methods extends Record < string , any > > (
429+ /**
430+ * Creates a filtered plugin with setup context using type guard.
431+ *
432+ * @param condition - Type guard function that determines if plugin applies
433+ * @param methods - Function that receives filtered element and setup context, returns plugin methods
434+ * @returns Plugin that applies only to elements matching the type guard with setup context
435+ */
436+ < const T , const Methods extends Record < string , any > > (
357437 condition : ( element : unknown ) => element is T ,
358438 methods : ( element : T , context : TSetupContext ) => Methods ,
359439 ) : Plugin < {
360440 ( element : T ) : Methods
361- ( element : any ) : { }
362441 } >
363442 }
364443 }
365444}
366445
367- export type InferPluginProps < TPlugins extends Plugin [ ] > = Merge < {
368- [ TKey in keyof TPlugins ] : TPlugins [ TKey ] extends ( ) => ( element : any ) => infer U
369- ? { [ TKey in keyof U ] : U [ TKey ] extends ( callback : infer V ) => any ? V : never }
370- : never
371- } >
372-
373- /**
374- * Helper type to resolve overloaded function returns
375- * Matches overloads from most specific to least specific
376- */
377- type ResolvePluginReturn < TFn , TTarget > = TFn extends {
378- ( element : infer P1 ) : infer R1
379- ( element : infer P2 ) : infer R2
380- ( element : infer P3 ) : infer R3
381- ( element : infer P4 ) : infer R4
382- ( element : infer P5 ) : infer R5
383- }
384- ? TTarget extends P1
385- ? R1
386- : TTarget extends P2
387- ? R2
388- : TTarget extends P3
389- ? R3
390- : TTarget extends P4
391- ? R4
392- : TTarget extends P5
393- ? R5
394- : never
395- : TFn extends {
396- ( element : infer P1 ) : infer R1
397- ( element : infer P2 ) : infer R2
398- ( element : infer P3 ) : infer R3
399- ( element : infer P4 ) : infer R4
400- }
401- ? TTarget extends P1
402- ? R1
403- : TTarget extends P2
404- ? R2
405- : TTarget extends P3
406- ? R3
407- : TTarget extends P4
408- ? R4
409- : never
410- : TFn extends {
411- ( element : infer P1 ) : infer R1
412- ( element : infer P2 ) : infer R2
413- ( element : infer P3 ) : infer R3
414- }
415- ? TTarget extends P1
416- ? R1
417- : TTarget extends P2
418- ? R2
419- : TTarget extends P3
420- ? R3
421- : never
422- : TFn extends { ( element : infer P1 ) : infer R1 ; ( element : infer P2 ) : infer R2 }
423- ? TTarget extends P1
424- ? R1
425- : TTarget extends P2
426- ? R2
427- : never
428- : TFn extends { ( element : infer P ) : infer R }
429- ? TTarget extends P
430- ? R
431- : never
432- : never
433-
434- /**
435- * Resolves what a plugin returns for a specific element type T
436- * Handles both simple functions and overloaded functions
437- */
438446type PluginReturn < TPlugin , TKind > = TPlugin extends Plugin < infer TFn >
439- ? TFn extends ( ...args : any [ ] ) => any
440- ? ResolvePluginReturn < TFn , TKind > extends infer TResult
441- ? TResult extends never
442- ? TFn extends ( element : TKind ) => infer R
443- ? R
444- : TFn extends ( element : any ) => infer R
445- ? R
446- : { }
447- : TResult
447+ ? TFn extends { ( element : infer P ) : infer R }
448+ ? TKind extends P
449+ ? R
448450 : { }
449451 : { }
450452 : { }
@@ -453,12 +455,13 @@ type PluginReturn<TPlugin, TKind> = TPlugin extends Plugin<infer TFn>
453455 * Resolves plugin props for a specific element type T
454456 * This allows plugins to provide conditional methods based on the actual element type
455457 */
456- export type PluginPropsOf < T , TPlugins extends Plugin [ ] > = Merge < {
457- [ K in keyof TPlugins ] : PluginReturn < TPlugins [ K ] , T > extends infer Methods
458- ? Methods extends Record < string , any >
459- ? {
460- [ M in keyof Methods ] : Methods [ M ] extends ( value : infer V ) => any ? V : never
461- }
462- : { }
458+ export type InferPluginProps < T , TPlugins extends Plugin [ ] > = Merge < {
459+ [ K in keyof TPlugins ] : PluginReturn < TPlugins [ K ] , T > extends infer Methods extends Record <
460+ string ,
461+ any
462+ >
463+ ? {
464+ [ M in keyof Methods ] : Methods [ M ] extends ( value : infer V ) => any ? V : never
465+ }
463466 : { }
464467} >
0 commit comments