@@ -5,7 +5,7 @@ import InlineComponentWrapper from '../InlineComponent';
5
5
import get_object from '../../../utils/get_object' ;
6
6
import replace_object from '../../../utils/replace_object' ;
7
7
import Block from '../../Block' ;
8
- import Renderer from '../../Renderer' ;
8
+ import Renderer , { BindingGroup } from '../../Renderer' ;
9
9
import flatten_reference from '../../../utils/flatten_reference' ;
10
10
import { Node , Identifier } from 'estree' ;
11
11
import add_to_set from '../../../utils/add_to_set' ;
@@ -26,6 +26,7 @@ export default class BindingWrapper {
26
26
snippet : Node ;
27
27
is_readonly : boolean ;
28
28
needs_lock : boolean ;
29
+ binding_group : BindingGroup ;
29
30
30
31
constructor ( block : Block , node : Binding , parent : ElementWrapper | InlineComponentWrapper ) {
31
32
this . node = node ;
@@ -45,6 +46,10 @@ export default class BindingWrapper {
45
46
46
47
this . object = get_object ( this . node . expression . node ) . name ;
47
48
49
+ if ( this . node . name === 'group' ) {
50
+ this . binding_group = get_binding_group ( parent . renderer , this , block ) ;
51
+ }
52
+
48
53
// view to model
49
54
this . handler = get_event_handler ( this , parent . renderer , block , this . object , this . node . raw_expression ) ;
50
55
@@ -67,6 +72,10 @@ export default class BindingWrapper {
67
72
}
68
73
} ) ;
69
74
75
+ if ( this . binding_group ) {
76
+ this . binding_group . list_dependencies . forEach ( dep => dependencies . add ( dep ) ) ;
77
+ }
78
+
70
79
return dependencies ;
71
80
}
72
81
@@ -105,6 +114,7 @@ export default class BindingWrapper {
105
114
106
115
const update_conditions : any [ ] = this . needs_lock ? [ x `!${ lock } ` ] : [ ] ;
107
116
const mount_conditions : any [ ] = [ ] ;
117
+ let update_or_condition : any = null ;
108
118
109
119
const dependency_array = Array . from ( this . get_dependencies ( ) ) ;
110
120
@@ -142,33 +152,12 @@ export default class BindingWrapper {
142
152
switch ( this . node . name ) {
143
153
case 'group' :
144
154
{
145
- const { binding_group, is_context, contexts, index, keypath } = get_binding_group ( parent . renderer , this . node , block ) ;
146
-
147
155
block . renderer . add_to_context ( '$$binding_groups' ) ;
156
+ this . binding_group . elements . push ( this . parent . var ) ;
148
157
149
- if ( is_context && ! block . binding_group_initialised . has ( keypath ) ) {
150
- if ( contexts . length > 1 ) {
151
- let binding_group = x `${ block . renderer . reference ( '$$binding_groups' ) } [${ index } ]` ;
152
- for ( const name of contexts . slice ( 0 , - 1 ) ) {
153
- binding_group = x `${ binding_group } [${ block . renderer . reference ( name ) } ]` ;
154
- block . chunks . init . push (
155
- b `${ binding_group } = ${ binding_group } || [];`
156
- ) ;
157
- }
158
- }
159
- block . chunks . init . push (
160
- b `${ binding_group ( true ) } = [];`
161
- ) ;
162
- block . binding_group_initialised . add ( keypath ) ;
158
+ if ( ( this . parent as ElementWrapper ) . has_dynamic_value ) {
159
+ update_or_condition = ( this . parent as ElementWrapper ) . dynamic_value_condition ;
163
160
}
164
-
165
- block . chunks . hydrate . push (
166
- b `${ binding_group ( true ) } .push(${ parent . var } );`
167
- ) ;
168
-
169
- block . chunks . destroy . push (
170
- b `${ binding_group ( true ) } .splice(${ binding_group ( true ) } .indexOf(${ parent . var } ), 1);`
171
- ) ;
172
161
break ;
173
162
}
174
163
@@ -214,7 +203,8 @@ export default class BindingWrapper {
214
203
215
204
if ( update_dom ) {
216
205
if ( update_conditions . length > 0 ) {
217
- const condition = update_conditions . reduce ( ( lhs , rhs ) => x `${ lhs } && ${ rhs } ` ) ;
206
+ let condition = update_conditions . reduce ( ( lhs , rhs ) => x `${ lhs } && ${ rhs } ` ) ;
207
+ if ( update_or_condition ) condition = x `${ update_or_condition } || (${ condition } )` ;
218
208
219
209
block . chunks . update . push ( b `
220
210
if (${ condition } ) {
@@ -279,7 +269,8 @@ function get_dom_updater(
279
269
return b `${ element . var } .${ binding . node . name } = ${ binding . snippet } ;` ;
280
270
}
281
271
282
- function get_binding_group ( renderer : Renderer , value : Binding , block : Block ) {
272
+ function get_binding_group ( renderer : Renderer , binding : BindingWrapper , block : Block ) {
273
+ const value = binding . node ;
283
274
const { parts } = flatten_reference ( value . raw_expression ) ;
284
275
let keypath = parts . join ( '.' ) ;
285
276
@@ -314,41 +305,75 @@ function get_binding_group(renderer: Renderer, value: Binding, block: Block) {
314
305
contexts . push ( name ) ;
315
306
}
316
307
308
+ // create a global binding_group across blocks
317
309
if ( ! renderer . binding_groups . has ( keypath ) ) {
318
310
const index = renderer . binding_groups . size ;
311
+ // the bind:group depends on the list in the {#each} block as well
312
+ // as reordering (removing and adding back to the DOM) may affect the value
313
+ const list_dependencies = new Set < string > ( ) ;
314
+ let parent = value . parent ;
315
+ while ( parent ) {
316
+ if ( parent . type === 'EachBlock' ) {
317
+ for ( const dep of parent . expression . dynamic_dependencies ( ) ) {
318
+ list_dependencies . add ( dep ) ;
319
+ }
320
+ }
321
+ parent = parent . parent ;
322
+ }
323
+
324
+ const elements = [ ] ;
319
325
320
326
contexts . forEach ( context => {
321
327
renderer . add_to_context ( context , true ) ;
322
328
} ) ;
323
329
324
330
renderer . binding_groups . set ( keypath , {
325
- binding_group : ( to_reference : boolean = false ) => {
326
- let binding_group = '$$binding_groups' ;
327
- let _secondary_indexes = contexts ;
331
+ binding_group : ( ) => {
332
+ let obj = x `$$binding_groups[${ index } ]` ;
328
333
329
- if ( to_reference ) {
330
- binding_group = block . renderer . reference ( binding_group ) ;
331
- _secondary_indexes = _secondary_indexes . map ( name => block . renderer . reference ( name ) ) ;
332
- }
333
-
334
- if ( _secondary_indexes . length > 0 ) {
335
- let obj = x `${ binding_group } [${ index } ]` ;
336
- _secondary_indexes . forEach ( secondary_index => {
334
+ if ( contexts . length > 0 ) {
335
+ contexts . forEach ( secondary_index => {
337
336
obj = x `${ obj } [${ secondary_index } ]` ;
338
337
} ) ;
339
- return obj ;
340
- } else {
341
- return x `${ binding_group } [${ index } ]` ;
342
338
}
339
+ return obj ;
343
340
} ,
344
- is_context : contexts . length > 0 ,
345
341
contexts,
346
- index,
347
- keypath
342
+ list_dependencies,
343
+ keypath,
344
+ elements,
345
+ render ( ) {
346
+ const local_name = block . get_unique_name ( 'binding_group' ) ;
347
+ const binding_group = block . renderer . reference ( '$$binding_groups' ) ;
348
+ block . add_variable ( local_name ) ;
349
+ if ( contexts . length > 0 ) {
350
+ const indexes = { type : 'ArrayExpression' , elements : contexts . map ( name => block . renderer . reference ( name ) ) } ;
351
+ block . chunks . init . push (
352
+ b `${ local_name } = @init_binding_group_dynamic(${ binding_group } [${ index } ], ${ indexes } )`
353
+ ) ;
354
+ block . chunks . update . push (
355
+ b `if (${ block . renderer . dirty ( Array . from ( list_dependencies ) ) } ) ${ local_name } .u(${ indexes } )`
356
+ ) ;
357
+ } else {
358
+ block . chunks . init . push (
359
+ b `${ local_name } = @init_binding_group(${ binding_group } [${ index } ])`
360
+ ) ;
361
+ }
362
+ block . chunks . hydrate . push (
363
+ b `${ local_name } .p(${ elements } )`
364
+ ) ;
365
+ block . chunks . destroy . push (
366
+ b `${ local_name } .r()`
367
+ ) ;
368
+ }
348
369
} ) ;
349
370
}
350
371
351
- return renderer . binding_groups . get ( keypath ) ;
372
+ // register the binding_group for the block
373
+ const binding_group = renderer . binding_groups . get ( keypath ) ;
374
+ block . binding_groups . add ( binding_group ) ;
375
+
376
+ return binding_group ;
352
377
}
353
378
354
379
function get_event_handler (
@@ -386,7 +411,7 @@ function get_event_handler(
386
411
}
387
412
}
388
413
389
- const value = get_value_from_dom ( renderer , binding . parent , binding , block , contextual_dependencies ) ;
414
+ const value = get_value_from_dom ( renderer , binding . parent , binding , contextual_dependencies ) ;
390
415
391
416
const mutation = b `
392
417
${ lhs } = ${ value } ;
@@ -402,10 +427,9 @@ function get_event_handler(
402
427
}
403
428
404
429
function get_value_from_dom (
405
- renderer : Renderer ,
430
+ _renderer : Renderer ,
406
431
element : ElementWrapper | InlineComponentWrapper ,
407
432
binding : BindingWrapper ,
408
- block : Block ,
409
433
contextual_dependencies : Set < string >
410
434
) {
411
435
const { node } = element ;
@@ -427,7 +451,7 @@ function get_value_from_dom(
427
451
// <input type='checkbox' bind:group='foo'>
428
452
if ( name === 'group' ) {
429
453
if ( type === 'checkbox' ) {
430
- const { binding_group, contexts } = get_binding_group ( renderer , binding . node , block ) ;
454
+ const { binding_group, contexts } = binding . binding_group ;
431
455
add_to_set ( contextual_dependencies , contexts ) ;
432
456
return x `@get_binding_group_value(${ binding_group ( ) } , this.__value, this.checked)` ;
433
457
}
0 commit comments