leaner 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +2 -1
- package/dist/web.js +223 -55
- package/package.json +1 -1
- package/types/core.d.ts +1 -1
package/dist/core.js
CHANGED
|
@@ -540,8 +540,9 @@ function watch( getter, callback ) {
|
|
|
540
540
|
updateWatcher( watcher, newDeps );
|
|
541
541
|
|
|
542
542
|
if ( newValue !== value ) {
|
|
543
|
-
|
|
543
|
+
const oldValue = value;
|
|
544
544
|
value = newValue;
|
|
545
|
+
callback( newValue, oldValue );
|
|
545
546
|
}
|
|
546
547
|
}
|
|
547
548
|
}
|
package/dist/web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { withScope, destroyScope, reactive, constant } from 'leaner';
|
|
1
|
+
import { withScope, destroyScope, reactive, constant, state } from 'leaner';
|
|
2
2
|
|
|
3
3
|
function appendToArray( item, target ) {
|
|
4
4
|
if ( Array.isArray( item ) )
|
|
@@ -111,31 +111,35 @@ function mountContext( context ) {
|
|
|
111
111
|
mountContext( child );
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
withContext( context, () => {
|
|
115
|
+
if ( context.refs != null ) {
|
|
116
|
+
for ( const ref of context.refs )
|
|
117
|
+
ref.callback( ref.element );
|
|
118
|
+
}
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
if ( context.mount != null ) {
|
|
121
|
+
for ( const callback of context.mount )
|
|
122
|
+
callback();
|
|
123
|
+
}
|
|
124
|
+
} );
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
function destroyContext( context ) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
callback
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
withContext( context, () => {
|
|
129
|
+
if ( context.destroy != null ) {
|
|
130
|
+
for ( const callback of context.destroy )
|
|
131
|
+
callback();
|
|
132
|
+
context.destroy = null;
|
|
133
|
+
}
|
|
131
134
|
|
|
132
|
-
|
|
135
|
+
if ( context.refs != null ) {
|
|
136
|
+
for ( const ref of context.refs )
|
|
137
|
+
ref.callback( null );
|
|
138
|
+
context.refs = null;
|
|
139
|
+
}
|
|
140
|
+
} );
|
|
133
141
|
|
|
134
|
-
|
|
135
|
-
for ( const ref of context.refs )
|
|
136
|
-
ref.callback( null );
|
|
137
|
-
context.refs = null;
|
|
138
|
-
}
|
|
142
|
+
context.mount = null;
|
|
139
143
|
|
|
140
144
|
if ( context.scope.length > 0 ) {
|
|
141
145
|
destroyScope( context.scope );
|
|
@@ -162,6 +166,9 @@ function provide( key, value ) {
|
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
function inject( key ) {
|
|
169
|
+
if ( current == null )
|
|
170
|
+
throw new Error( 'inject() cannot be called outside of a component' );
|
|
171
|
+
|
|
165
172
|
for ( let context = current; context != null; context = context.parent ) {
|
|
166
173
|
if ( context.services != null && context.services.has( key ) )
|
|
167
174
|
return context.services.get( key );
|
|
@@ -295,12 +302,18 @@ function removeNode( node ) {
|
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
function replaceNode( newNode, node ) {
|
|
305
|
+
// this is safe because the parent of a DynamicNode is always a true DOM node
|
|
306
|
+
const parent = Array.isArray( node ) ? node[ 0 ].parentNode : node.parentNode;
|
|
307
|
+
|
|
308
|
+
// remember the value of a <select> element so that it can be restored later
|
|
309
|
+
const currentValue = parent instanceof HTMLSelectElement ? parent.value : null;
|
|
310
|
+
|
|
298
311
|
if ( newNode instanceof Node && node instanceof Node ) {
|
|
299
|
-
|
|
312
|
+
parent.replaceChild( newNode, node );
|
|
300
313
|
} else if ( Array.isArray( newNode ) && Array.isArray( node ) ) {
|
|
301
314
|
let newStart = 0, start = 0;
|
|
302
315
|
let newEnd = newNode.length, end = node.length;
|
|
303
|
-
let
|
|
316
|
+
let before;
|
|
304
317
|
|
|
305
318
|
while ( newStart < newEnd || start < end ) {
|
|
306
319
|
// skip equal nodes at the start
|
|
@@ -324,13 +337,15 @@ function replaceNode( newNode, node ) {
|
|
|
324
337
|
before = node[ start ];
|
|
325
338
|
if ( before instanceof DynamicNode )
|
|
326
339
|
before = findFirstChild( before.content );
|
|
327
|
-
|
|
328
|
-
} else {
|
|
340
|
+
} else if ( newStart > 0 ) {
|
|
329
341
|
let after = newNode[ newStart - 1 ];
|
|
330
342
|
if ( after instanceof DynamicNode )
|
|
331
343
|
after = findLastChild( after.content );
|
|
332
344
|
before = after.nextSibling;
|
|
333
|
-
|
|
345
|
+
} else {
|
|
346
|
+
before = newNode[ newEnd ];
|
|
347
|
+
if ( before instanceof DynamicNode )
|
|
348
|
+
before = findFirstChild( before.content );
|
|
334
349
|
}
|
|
335
350
|
}
|
|
336
351
|
insertBefore( newNode[ newStart ], parent, before );
|
|
@@ -352,7 +367,6 @@ function replaceNode( newNode, node ) {
|
|
|
352
367
|
before = node[ start ];
|
|
353
368
|
if ( before instanceof DynamicNode )
|
|
354
369
|
before = findFirstChild( before.content );
|
|
355
|
-
parent = before.parentNode;
|
|
356
370
|
}
|
|
357
371
|
insertBefore( node[ end - 1 ], parent, before );
|
|
358
372
|
|
|
@@ -375,10 +389,12 @@ function replaceNode( newNode, node ) {
|
|
|
375
389
|
} else {
|
|
376
390
|
const after = findLastChild( node );
|
|
377
391
|
const before = after.nextSibling;
|
|
378
|
-
const parent = after.parentNode;
|
|
379
392
|
removeNode( node );
|
|
380
393
|
insertBefore( newNode, parent, before );
|
|
381
394
|
}
|
|
395
|
+
|
|
396
|
+
if ( currentValue != null )
|
|
397
|
+
parent.value = currentValue;
|
|
382
398
|
}
|
|
383
399
|
|
|
384
400
|
function findFirstChild( node ) {
|
|
@@ -471,12 +487,16 @@ function createForDirective( template ) {
|
|
|
471
487
|
throw new TypeError( 'Invalid for template' );
|
|
472
488
|
|
|
473
489
|
const itemsGetter = template[ 1 ];
|
|
490
|
+
const callback = template[ 2 ];
|
|
491
|
+
const useIndexes = callback.length > 1;
|
|
474
492
|
|
|
475
493
|
let length = 0;
|
|
476
494
|
let items = null;
|
|
477
495
|
|
|
478
496
|
let watchingContent = false;
|
|
479
497
|
|
|
498
|
+
let indexStates = null;
|
|
499
|
+
|
|
480
500
|
const result = new DynamicNode( null );
|
|
481
501
|
|
|
482
502
|
const context = createChildContext();
|
|
@@ -516,6 +536,8 @@ function createForDirective( template ) {
|
|
|
516
536
|
oldIndexMap.set( items[ i ], i );
|
|
517
537
|
}
|
|
518
538
|
|
|
539
|
+
let newIndexStates = null;
|
|
540
|
+
|
|
519
541
|
for ( let index = 0; index < newItems.length; index++ ) {
|
|
520
542
|
const value = newItems[ index ];
|
|
521
543
|
|
|
@@ -545,6 +567,16 @@ function createForDirective( template ) {
|
|
|
545
567
|
|
|
546
568
|
if ( oldItemContexts != null )
|
|
547
569
|
oldItemContexts.delete( itemContext );
|
|
570
|
+
|
|
571
|
+
if ( useIndexes && isMatchedByValue ) {
|
|
572
|
+
// update the index passed to the child if it's reordered
|
|
573
|
+
const indexState = indexStates.get( oldIndex );
|
|
574
|
+
if ( oldIndex != index )
|
|
575
|
+
indexState[ 1 ]( index );
|
|
576
|
+
if ( newIndexStates == null )
|
|
577
|
+
newIndexStates = new Map();
|
|
578
|
+
newIndexStates.set( index, indexState );
|
|
579
|
+
}
|
|
548
580
|
} else {
|
|
549
581
|
const itemContext = createContext( context );
|
|
550
582
|
itemContexts.push( itemContext );
|
|
@@ -555,7 +587,26 @@ function createForDirective( template ) {
|
|
|
555
587
|
|
|
556
588
|
const item = isMatchedByValue ? constant( value ) : itemsGetter[ index ];
|
|
557
589
|
|
|
558
|
-
|
|
590
|
+
let itemTemplate;
|
|
591
|
+
|
|
592
|
+
if ( useIndexes ) {
|
|
593
|
+
let indexGetter;
|
|
594
|
+
|
|
595
|
+
if ( isMatchedByValue ) {
|
|
596
|
+
// index can change in the future - use reactive state
|
|
597
|
+
const indexState = state( index );
|
|
598
|
+
if ( newIndexStates == null )
|
|
599
|
+
newIndexStates = new Map();
|
|
600
|
+
newIndexStates.set( index, indexState );
|
|
601
|
+
indexGetter = indexState[ 0 ];
|
|
602
|
+
} else {
|
|
603
|
+
indexGetter = constant( index );
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
itemTemplate = callback( item, indexGetter );
|
|
607
|
+
} else {
|
|
608
|
+
itemTemplate = callback( item );
|
|
609
|
+
}
|
|
559
610
|
|
|
560
611
|
const node = withContext( itemContext, () => make( itemTemplate ) );
|
|
561
612
|
|
|
@@ -588,6 +639,8 @@ function createForDirective( template ) {
|
|
|
588
639
|
else
|
|
589
640
|
context.children = null;
|
|
590
641
|
|
|
642
|
+
indexStates = newIndexStates;
|
|
643
|
+
|
|
591
644
|
if ( containsMatchedByValue && !watchingContent ) {
|
|
592
645
|
destroyScope( context.scope );
|
|
593
646
|
context.scope = [];
|
|
@@ -601,20 +654,8 @@ function createForDirective( template ) {
|
|
|
601
654
|
}
|
|
602
655
|
|
|
603
656
|
function createIfDirective( template ) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
for ( let i = 1; i < template.length; i += 2 ) {
|
|
608
|
-
if ( i == template.length - 1 )
|
|
609
|
-
hasElse = true;
|
|
610
|
-
else if ( typeof template[ i ] == 'function' )
|
|
611
|
-
numberOfConditions++;
|
|
612
|
-
else
|
|
613
|
-
throw new TypeError( 'Invalid if template' );
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
if ( numberOfConditions == 0 )
|
|
617
|
-
throw new TypeError( 'Invalid if template' );
|
|
657
|
+
if ( template.length < 2 || typeof template[ 1 ] != 'function' )
|
|
658
|
+
throw new TypeError( 'Invalid if template' );
|
|
618
659
|
|
|
619
660
|
const result = new DynamicNode( null );
|
|
620
661
|
|
|
@@ -625,23 +666,88 @@ function createIfDirective( template ) {
|
|
|
625
666
|
return result;
|
|
626
667
|
|
|
627
668
|
function watchState() {
|
|
628
|
-
|
|
669
|
+
return template[ 1 ]();
|
|
670
|
+
}
|
|
629
671
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
672
|
+
function update( state ) {
|
|
673
|
+
let childTemplate = null;
|
|
674
|
+
if ( state ) {
|
|
675
|
+
if ( template.length == 3 )
|
|
676
|
+
childTemplate = template[ 2 ];
|
|
677
|
+
else
|
|
678
|
+
childTemplate = [ template.slice( 2 ) ];
|
|
635
679
|
}
|
|
680
|
+
updateDynamicNode( result, context, childTemplate );
|
|
681
|
+
}
|
|
682
|
+
}
|
|
636
683
|
|
|
637
|
-
|
|
638
|
-
|
|
684
|
+
function createRepeatDirective( template ) {
|
|
685
|
+
if ( template.length != 3 || typeof template[ 2 ] != 'function' )
|
|
686
|
+
throw new TypeError( 'Invalid repeat template' );
|
|
639
687
|
|
|
640
|
-
|
|
688
|
+
let count = 0;
|
|
689
|
+
|
|
690
|
+
const result = new DynamicNode( null );
|
|
691
|
+
|
|
692
|
+
const context = createChildContext();
|
|
693
|
+
|
|
694
|
+
if ( typeof template[ 1 ] == 'function' ) {
|
|
695
|
+
withScope( context.scope, () => {
|
|
696
|
+
reactive( template[ 1 ], updateCount );
|
|
697
|
+
} );
|
|
698
|
+
} else {
|
|
699
|
+
updateCount( template[ 1 ] );
|
|
641
700
|
}
|
|
642
701
|
|
|
643
|
-
|
|
644
|
-
|
|
702
|
+
return result;
|
|
703
|
+
|
|
704
|
+
function updateCount( newCount ) {
|
|
705
|
+
if ( newCount > count ) {
|
|
706
|
+
const nodes = result.content != null ? result.content.slice( 0, count ) : [];
|
|
707
|
+
const contexts = context.children != null ? context.children.slice( 0, count ) : [];
|
|
708
|
+
|
|
709
|
+
for ( let i = count; i < newCount; i++ ) {
|
|
710
|
+
const itemContext = createContext( context );
|
|
711
|
+
contexts.push( itemContext );
|
|
712
|
+
|
|
713
|
+
const itemTemplate = template[ 2 ]( i );
|
|
714
|
+
|
|
715
|
+
const node = withContext( itemContext, () => make( itemTemplate ) );
|
|
716
|
+
|
|
717
|
+
if ( Array.isArray( node ) )
|
|
718
|
+
nodes.push( new DynamicNode( node ) );
|
|
719
|
+
else
|
|
720
|
+
nodes.push( node );
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if ( result.content != null ) {
|
|
724
|
+
replaceNode( nodes, result.content );
|
|
725
|
+
|
|
726
|
+
for ( let i = count; i < newCount; i++ )
|
|
727
|
+
mountContext( contexts[ i ] );
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
result.content = nodes;
|
|
731
|
+
context.children = contexts;
|
|
732
|
+
} else {
|
|
733
|
+
for ( let i = newCount; i < count; i++ )
|
|
734
|
+
destroyContext( context.children[ i ] );
|
|
735
|
+
|
|
736
|
+
const nodes = result.content != null ? result.content.slice( 0, newCount ) : [];
|
|
737
|
+
ensureNotEmpty( nodes );
|
|
738
|
+
|
|
739
|
+
if ( result.content != null )
|
|
740
|
+
replaceNode( nodes, result.content );
|
|
741
|
+
|
|
742
|
+
result.content = nodes;
|
|
743
|
+
|
|
744
|
+
if ( newCount == 0 )
|
|
745
|
+
context.children = null;
|
|
746
|
+
else if ( context.children != null )
|
|
747
|
+
context.children = context.children.slice( 0, newCount );
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
count = newCount;
|
|
645
751
|
}
|
|
646
752
|
}
|
|
647
753
|
|
|
@@ -683,10 +789,68 @@ function setStyleProperty( element, key, value ) {
|
|
|
683
789
|
element.style[ key ] = value;
|
|
684
790
|
}
|
|
685
791
|
|
|
792
|
+
function createSwitchDirective( template ) {
|
|
793
|
+
let numberOfConditions = 0;
|
|
794
|
+
let hasElse = false;
|
|
795
|
+
|
|
796
|
+
for ( let i = 1; i < template.length; i++ ) {
|
|
797
|
+
const condition = template[ i ];
|
|
798
|
+
if ( Array.isArray( condition ) && condition.length > 1 && condition[ 0 ] === 'if' && typeof condition[ 1 ] == 'function' )
|
|
799
|
+
numberOfConditions++;
|
|
800
|
+
else if ( i == template.length - 1 && Array.isArray( condition ) && condition.length > 0 && condition[ 0 ] === 'else' )
|
|
801
|
+
hasElse = true;
|
|
802
|
+
else
|
|
803
|
+
throw new TypeError( 'Invalid switch template' );
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if ( numberOfConditions == 0 )
|
|
807
|
+
throw new TypeError( 'Invalid switch template' );
|
|
808
|
+
|
|
809
|
+
const result = new DynamicNode( null );
|
|
810
|
+
|
|
811
|
+
const context = createChildContext();
|
|
812
|
+
|
|
813
|
+
reactive( watchState, update );
|
|
814
|
+
|
|
815
|
+
return result;
|
|
816
|
+
|
|
817
|
+
function watchState() {
|
|
818
|
+
let state = null;
|
|
819
|
+
|
|
820
|
+
for ( let i = 0; i < numberOfConditions; i++ ) {
|
|
821
|
+
if ( template[ i + 1 ][ 1 ]() ) {
|
|
822
|
+
state = i + 1;
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if ( state == null && hasElse )
|
|
828
|
+
state = template.length - 1;
|
|
829
|
+
|
|
830
|
+
return state;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function update( state ) {
|
|
834
|
+
let childTemplate = null;
|
|
835
|
+
if ( state != null ) {
|
|
836
|
+
const condition = template[ state ];
|
|
837
|
+
const index = condition[ 0 ] == 'else' ? 1 : 2;
|
|
838
|
+
if ( condition.length == index + 1 )
|
|
839
|
+
childTemplate = condition[ index ];
|
|
840
|
+
else
|
|
841
|
+
childTemplate = [ condition.slice( index ) ];
|
|
842
|
+
}
|
|
843
|
+
updateDynamicNode( result, context, childTemplate );
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
686
847
|
const Directives = {
|
|
687
|
-
if: createIfDirective,
|
|
688
|
-
for: createForDirective,
|
|
689
848
|
dynamic: createDynamicDirective,
|
|
849
|
+
else: unexpectedDirective,
|
|
850
|
+
for: createForDirective,
|
|
851
|
+
if: createIfDirective,
|
|
852
|
+
repeat: createRepeatDirective,
|
|
853
|
+
switch: createSwitchDirective,
|
|
690
854
|
};
|
|
691
855
|
|
|
692
856
|
const Properties = new Set( [ 'value', 'checked', 'textContent', 'innerHTML' ] );
|
|
@@ -807,6 +971,10 @@ function setElementAttribute( element, name, value ) {
|
|
|
807
971
|
}
|
|
808
972
|
}
|
|
809
973
|
|
|
974
|
+
function unexpectedDirective( template ) {
|
|
975
|
+
throw new TypeError( `Unexpected ${template[ 0 ]} directive` );
|
|
976
|
+
}
|
|
977
|
+
|
|
810
978
|
function createApp( component ) {
|
|
811
979
|
const context = createContext( null );
|
|
812
980
|
|
package/package.json
CHANGED
package/types/core.d.ts
CHANGED