@@ -4,6 +4,7 @@ import Renderer from '../../Renderer';
4
4
import Block from '../../Block' ;
5
5
import InlineComponent from '../../../nodes/InlineComponent' ;
6
6
import FragmentWrapper from '../Fragment' ;
7
+ import SlotTemplateWrapper from '../SlotTemplate' ;
7
8
import { sanitize } from '../../../../utils/names' ;
8
9
import add_to_set from '../../../utils/add_to_set' ;
9
10
import { b , x , p } from 'code-red' ;
@@ -19,11 +20,15 @@ import { extract_names } from 'periscopic';
19
20
import mark_each_block_bindings from '../shared/mark_each_block_bindings' ;
20
21
import { string_to_member_expression } from '../../../utils/string_to_member_expression' ;
21
22
23
+ type SlotDefinition = { block : Block ; scope : TemplateScope ; get_context ?: Node ; get_changes ?: Node } ;
24
+
22
25
export default class InlineComponentWrapper extends Wrapper {
23
26
var : Identifier ;
24
- slots : Map < string , { block : Block ; scope : TemplateScope ; get_context ?: Node ; get_changes ?: Node } > = new Map ( ) ;
27
+ slots : Map < string , SlotDefinition > = new Map ( ) ;
25
28
node : InlineComponent ;
26
29
fragment : FragmentWrapper ;
30
+ children : Array < Wrapper | FragmentWrapper > = [ ] ;
31
+ default_slot_block : Block ;
27
32
28
33
constructor (
29
34
renderer : Renderer ,
@@ -76,16 +81,35 @@ export default class InlineComponentWrapper extends Wrapper {
76
81
} ) ;
77
82
} ) ;
78
83
84
+ const children = this . node . children . slice ( ) ;
85
+ for ( let i = children . length - 1 ; i >= 0 ; ) {
86
+ const child = children [ i ] ;
87
+ if ( child . type === 'SlotTemplate' || ( child . type === 'Element' && child . attributes . find ( attribute => attribute . name === 'slot' ) ) ) {
88
+ const slot_template = new SlotTemplateWrapper ( renderer , block , this , child , strip_whitespace , next_sibling ) ;
89
+ this . children . push ( slot_template ) ;
90
+ children . splice ( i , 1 ) ;
91
+ continue ;
92
+ }
93
+
94
+ i -- ;
95
+ }
96
+
97
+ if ( this . slots . has ( 'default' ) && children . filter ( node => ! ( node . type === 'Text' && node . data . trim ( ) === '' ) ) ) {
98
+ throw new Error ( 'Found elements without slot attribute when using slot="default"' ) ;
99
+ }
100
+
79
101
const default_slot = block . child ( {
80
102
comment : create_debugging_comment ( node , renderer . component ) ,
81
103
name : renderer . component . get_unique_name ( `create_default_slot` ) ,
82
104
type : 'slot'
83
105
} ) ;
84
106
85
107
this . renderer . blocks . push ( default_slot ) ;
108
+ this . default_slot_block = default_slot ;
86
109
87
110
this . slots . set ( 'default' , get_slot_definition ( default_slot , this . node . scope , this . node . lets ) ) ;
88
- this . fragment = new FragmentWrapper ( renderer , default_slot , node . children , this , strip_whitespace , next_sibling ) ;
111
+ const fragment = new FragmentWrapper ( renderer , default_slot , children , this , strip_whitespace , next_sibling ) ;
112
+ this . children . push ( fragment ) ;
89
113
90
114
const dependencies : Set < string > = new Set ( ) ;
91
115
@@ -102,6 +126,13 @@ export default class InlineComponentWrapper extends Wrapper {
102
126
block . add_outro ( ) ;
103
127
}
104
128
129
+ set_slot ( name : string , slot_definition : SlotDefinition ) {
130
+ if ( this . slots . has ( name ) ) {
131
+ throw new Error ( `Duplicate slot name "${ name } " in <${ this . node . name } >` ) ;
132
+ }
133
+ this . slots . set ( name , slot_definition ) ;
134
+ }
135
+
105
136
warn_if_reactive ( ) {
106
137
const { name } = this . node ;
107
138
const variable = this . renderer . component . var_lookup . get ( name ) ;
@@ -135,14 +166,10 @@ export default class InlineComponentWrapper extends Wrapper {
135
166
const statements : Array < Node | Node [ ] > = [ ] ;
136
167
const updates : Array < Node | Node [ ] > = [ ] ;
137
168
138
- if ( this . fragment ) {
169
+ this . children . forEach ( ( child ) => {
139
170
this . renderer . add_to_context ( '$$scope' , true ) ;
140
- const default_slot = this . slots . get ( 'default' ) ;
141
-
142
- this . fragment . nodes . forEach ( ( child ) => {
143
- child . render ( default_slot . block , null , x `#nodes` as unknown as Identifier ) ;
144
- } ) ;
145
- }
171
+ child . render ( this . default_slot_block , null , x `#nodes` as Identifier ) ;
172
+ } ) ;
146
173
147
174
let props ;
148
175
const name_changes = block . get_unique_name ( `${ name . name } _changes` ) ;
@@ -194,7 +221,7 @@ export default class InlineComponentWrapper extends Wrapper {
194
221
component_opts . properties . push ( p `$$inline: true` ) ;
195
222
}
196
223
197
- const fragment_dependencies = new Set ( this . fragment ? [ '$$scope' ] : [ ] ) ;
224
+ const fragment_dependencies = new Set ( this . slots . size ? [ '$$scope' ] : [ ] ) ;
198
225
this . slots . forEach ( slot => {
199
226
slot . block . dependencies . forEach ( name => {
200
227
const is_let = slot . scope . is_let ( name ) ;
0 commit comments