@@ -534,3 +534,171 @@ test('handles empty slot symbols gracefully', () => {
534534 ]
535535 ` )
536536} )
537+
538+ test ( 'children after all slots are filled go to rest' , ( ) => {
539+ const calls : Array < ReturnType < typeof useSlots > > = [ ]
540+ const children = [
541+ < TestComponentA key = "a" > Slot A</ TestComponentA > ,
542+ < div key = "extra1" > Extra 1</ div > ,
543+ < div key = "extra2" > Extra 2</ div > ,
544+ < span key = "extra3" > Extra 3</ span > ,
545+ ]
546+ const slotsConfig = {
547+ a : TestComponentA ,
548+ }
549+
550+ function TestComponent ( _props : { children : React . ReactNode } ) {
551+ calls . push ( useSlots ( children , slotsConfig ) )
552+ return null
553+ }
554+
555+ render ( < TestComponent > { children } </ TestComponent > )
556+
557+ expect ( calls ) . toMatchInlineSnapshot ( `
558+ [
559+ [
560+ {
561+ "a": <TestComponentA>
562+ Slot A
563+ </TestComponentA>,
564+ },
565+ [
566+ <div>
567+ Extra 1
568+ </div>,
569+ <div>
570+ Extra 2
571+ </div>,
572+ <span>
573+ Extra 3
574+ </span>,
575+ ],
576+ ],
577+ ]
578+ ` )
579+ } )
580+
581+ test ( 'non-element children are placed in rest' , ( ) => {
582+ const calls : Array < ReturnType < typeof useSlots > > = [ ]
583+ const children = [
584+ 'plain text' ,
585+ null ,
586+ false ,
587+ < TestComponentA key = "a" > Slot</ TestComponentA > ,
588+ 0 ,
589+ < div key = "div" > Content</ div > ,
590+ ]
591+ const slotsConfig = {
592+ a : TestComponentA ,
593+ }
594+
595+ function TestComponent ( _props : { children : React . ReactNode } ) {
596+ calls . push ( useSlots ( children , slotsConfig ) )
597+ return null
598+ }
599+
600+ render ( < TestComponent > { children } </ TestComponent > )
601+
602+ const [ slots , rest ] = calls [ 0 ]
603+ expect ( slots . a ) . toBeDefined ( )
604+ // Non-element children (strings, numbers, null, false) go to rest
605+ // React.Children.forEach converts false to null
606+ expect ( rest ) . toMatchInlineSnapshot ( `
607+ [
608+ "plain text",
609+ null,
610+ null,
611+ 0,
612+ <div>
613+ Content
614+ </div>,
615+ ]
616+ ` )
617+ } )
618+
619+ test ( 'slots match regardless of child order' , ( ) => {
620+ const calls : Array < ReturnType < typeof useSlots > > = [ ]
621+ const children = [
622+ < div key = "text" > Text content</ div > ,
623+ < TestComponentB key = "b" > B</ TestComponentB > ,
624+ < TestComponentA key = "a" > A</ TestComponentA > ,
625+ ]
626+ const slotsConfig = {
627+ a : TestComponentA ,
628+ b : TestComponentB ,
629+ }
630+
631+ function TestComponent ( _props : { children : React . ReactNode } ) {
632+ calls . push ( useSlots ( children , slotsConfig ) )
633+ return null
634+ }
635+
636+ render ( < TestComponent > { children } </ TestComponent > )
637+
638+ expect ( calls ) . toMatchInlineSnapshot ( `
639+ [
640+ [
641+ {
642+ "a": <TestComponentA>
643+ A
644+ </TestComponentA>,
645+ "b": <TestComponentB>
646+ B
647+ </TestComponentB>,
648+ },
649+ [
650+ <div>
651+ Text content
652+ </div>,
653+ ],
654+ ],
655+ ]
656+ ` )
657+ } )
658+
659+ test ( 'single slot config short-circuits after first match' , ( ) => {
660+ const calls : Array < ReturnType < typeof useSlots > > = [ ]
661+ const children = [
662+ < TestComponentA key = "a" > Match</ TestComponentA > ,
663+ < div key = "1" > One</ div > ,
664+ < div key = "2" > Two</ div > ,
665+ < div key = "3" > Three</ div > ,
666+ < div key = "4" > Four</ div > ,
667+ ]
668+ const slotsConfig = {
669+ a : TestComponentA ,
670+ }
671+
672+ function TestComponent ( _props : { children : React . ReactNode } ) {
673+ calls . push ( useSlots ( children , slotsConfig ) )
674+ return null
675+ }
676+
677+ render ( < TestComponent > { children } </ TestComponent > )
678+
679+ expect ( calls ) . toMatchInlineSnapshot ( `
680+ [
681+ [
682+ {
683+ "a": <TestComponentA>
684+ Match
685+ </TestComponentA>,
686+ },
687+ [
688+ <div>
689+ One
690+ </div>,
691+ <div>
692+ Two
693+ </div>,
694+ <div>
695+ Three
696+ </div>,
697+ <div>
698+ Four
699+ </div>,
700+ ],
701+ ],
702+ ]
703+ ` )
704+ } )
0 commit comments