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