@srfnstack/fntags 1.1.2 → 1.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/package.json +1 -1
- package/src/fntags.d.mts.map +1 -1
- package/src/fntags.mjs +57 -33
package/package.json
CHANGED
package/src/fntags.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fntags.d.mts","sourceRoot":"","sources":["fntags.mjs"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,2DALW,MAAM,eACH,CAAC,IAAI,MAAO,CAAC,OA6C1B;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;GAGG;AAEH;;;;;;;;;;GAUG;AACH,iEAPgB,GAAG,cAoIlB;
|
|
1
|
+
{"version":3,"file":"fntags.d.mts","sourceRoot":"","sources":["fntags.mjs"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,2DALW,MAAM,eACH,CAAC,IAAI,MAAO,CAAC,OA6C1B;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;GAGG;AAEH;;;;;;;;;;GAUG;AACH,iEAPgB,GAAG,cAoIlB;AAgYD;;;;GAIG;AACH,iCAHW,GAAG,GACD,IAAI,CAuBhB;AAqFD;;;;GAIG;AACH,6BAHW,GAAG,GACD,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,GAAG,GACF,MAAM,CAIjB;AAED;;;;;;;;;;GAUG;AACH,kEALW,MAAM,GAAC,MAAM,OACb,MAAM,YACN,MAAM,EAAE,GAAC,IAAI,EAAE,KAezB;AAOD;;;;;;;;;;;;;;;GAeG;AACH,qDAJkB,IAAI,iBACH,IAAI,CA+DtB;;;;;;;;;kCAjxBmC,CAAC,YAAY,CAAC,KAAG,CAAC,IAAI,GAAC,GAAG,CAAC,KAAG,IAAI;;;;;;2BAE/C,CAAC,MAAI,CAAC,IAAI,GAAC,GAAG,CAAC,CAAC,GAAC,GAAG,GAAC,IAAI,gCAAkC,CAAC,IAAI,GAAC,GAAG,CAAC,KAAG,IAAI;;;;;qBAG9E,MAAM,KAAG,IAAI;;;;sCAEI,CAAC,YAAY,CAAC,KAAG,CAAC,MAAM,GAAC,GAAG,CAAC,KAAG,GAAG;;;;mCACvC,CAAC,YAAY,CAAC,KAAG,MAAM,KAAK,MAAM;;;;yCAC7B,GAAG,KAAG,CAAC,IAAI,GAAC,GAAG,CAAC,KAAG,IAAI;;;;+CACrB,GAAG,KAAG,CAAC,MAAM,GAAC,GAAG,CAAC,KAAG,GAAG;;;;;;kBAC7C,GAAG,KAAG,IAAI;;;;cAGhB,MAAK,GAAG;;;;;qBACC,CAAC,KAAG,IAAI;;;;;;oBAEV,MAAM,KAAG,GAAG;;;;oBAGZ,MAAM,SAAS,GAAG,mBAAmB,OAAO,KAAG,IAAI;;;;uCAClC,CAAC,YAAY,CAAC,KAAG,IAAI,KAAK,IAAI;;;;eACtD,OAAO;;;;;sDAKqB,CAAC,KAAG,CAAC"}
|
package/src/fntags.mjs
CHANGED
|
@@ -393,7 +393,7 @@ function doBindChildren (parent, element) {
|
|
|
393
393
|
if (!Array.isArray(ctx.currentValue)) {
|
|
394
394
|
throw new Error('You can only use bindChildren with a state that contains an array. try myState([mystate]) before calling this function.')
|
|
395
395
|
}
|
|
396
|
-
|
|
396
|
+
|
|
397
397
|
ctx.bindContexts.push({ element, parent })
|
|
398
398
|
this.subscribe((_, oldState) => {
|
|
399
399
|
if (!Array.isArray(ctx.currentValue)) {
|
|
@@ -490,60 +490,79 @@ function arrangeElements (ctx, bindContext, oldState) {
|
|
|
490
490
|
if (!ctx?.currentValue?.length) {
|
|
491
491
|
bindContext.parent.textContent = ''
|
|
492
492
|
bindContext.boundElementByKey = {}
|
|
493
|
+
bindContext.elementStates = {}
|
|
493
494
|
ctx.selectObservers = {}
|
|
494
495
|
return
|
|
495
496
|
}
|
|
496
497
|
|
|
498
|
+
// Initialize the element state map if it doesn't exist
|
|
499
|
+
if (!bindContext.elementStates) {
|
|
500
|
+
bindContext.elementStates = {}
|
|
501
|
+
}
|
|
502
|
+
|
|
497
503
|
const keys = {}
|
|
498
504
|
const keysArr = []
|
|
499
|
-
|
|
500
|
-
for (
|
|
501
|
-
|
|
502
|
-
//
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
oldStateMap = oldState && oldState.reduce((acc, v) => {
|
|
506
|
-
const key = keyMapper(ctx.mapKey, v.isFnState ? v() : v)
|
|
507
|
-
acc[key] = v
|
|
508
|
-
return acc
|
|
509
|
-
}, {})
|
|
510
|
-
}
|
|
511
|
-
// check if we have an old state for this key
|
|
512
|
-
const key = keyMapper(ctx.mapKey, valueState)
|
|
513
|
-
if (oldStateMap && oldStateMap[key]) {
|
|
514
|
-
const newValue = valueState
|
|
515
|
-
valueState = ctx.currentValue[i] = oldStateMap[key]
|
|
516
|
-
valueState(newValue)
|
|
517
|
-
} else {
|
|
518
|
-
valueState = ctx.currentValue[i] = fnstate(valueState)
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
const key = keyMapper(ctx.mapKey, valueState())
|
|
505
|
+
|
|
506
|
+
for (let i = 0; i < ctx.currentValue.length; i++) {
|
|
507
|
+
const rawValue = ctx.currentValue[i]
|
|
508
|
+
// Use the raw value to get the key
|
|
509
|
+
const key = keyMapper(ctx.mapKey, rawValue)
|
|
510
|
+
|
|
522
511
|
if (keys[key]) {
|
|
523
512
|
if (oldState) ctx.state(oldState)
|
|
524
513
|
throw new Error('Duplicate keys in a bound array are not allowed, state reset to previous value.')
|
|
525
514
|
}
|
|
515
|
+
|
|
526
516
|
keys[key] = i
|
|
527
517
|
keysArr[i] = key
|
|
518
|
+
|
|
519
|
+
// We look up the persistent fnstate for this key, or create it if new
|
|
520
|
+
let elementState = bindContext.elementStates[key]
|
|
521
|
+
if (!elementState) {
|
|
522
|
+
elementState = fnstate(rawValue)
|
|
523
|
+
// Ensure the parent state is set so child states can listen to selection changes
|
|
524
|
+
elementState.parentCtx = ctx
|
|
525
|
+
bindContext.elementStates[key] = elementState
|
|
526
|
+
// If the user replaces the value of this elementState (e.g. elementState(newObj)),
|
|
527
|
+
// we must update the original array to keep it in sync.
|
|
528
|
+
elementState.subscribe((newItem) => {
|
|
529
|
+
const currentArr = ctx.state()
|
|
530
|
+
// If the parent is no longer an array, abort
|
|
531
|
+
if (!Array.isArray(currentArr)) return
|
|
532
|
+
|
|
533
|
+
// find the element dynamically because sorting/filtering might have shifted the index
|
|
534
|
+
const idx = currentArr.findIndex(item => keyMapper(ctx.mapKey, item) === key)
|
|
535
|
+
|
|
536
|
+
if (idx > -1 && currentArr[idx] !== newItem) {
|
|
537
|
+
currentArr[idx] = newItem
|
|
538
|
+
}
|
|
539
|
+
})
|
|
540
|
+
} else {
|
|
541
|
+
// Update existing state with new raw value.
|
|
542
|
+
// fnstate handles the equality check (newValue !== oldValue) internally.
|
|
543
|
+
elementState(rawValue)
|
|
544
|
+
}
|
|
528
545
|
}
|
|
529
546
|
|
|
530
547
|
let prev = null
|
|
531
548
|
const parent = bindContext.parent
|
|
532
549
|
|
|
550
|
+
// 2. Render Loop
|
|
533
551
|
for (let i = ctx.currentValue.length - 1; i >= 0; i--) {
|
|
534
552
|
const key = keysArr[i]
|
|
535
|
-
|
|
553
|
+
// Retrieve the element state to pass to the builder
|
|
554
|
+
const valueState = bindContext.elementStates[key]
|
|
555
|
+
|
|
536
556
|
let current = bindContext.boundElementByKey[key]
|
|
537
557
|
let isNew = false
|
|
538
|
-
|
|
539
|
-
if (valueState.parentCtx === undefined) {
|
|
540
|
-
valueState.parentCtx = ctx
|
|
541
|
-
}
|
|
558
|
+
|
|
542
559
|
if (current === undefined) {
|
|
543
560
|
isNew = true
|
|
561
|
+
// Pass the valueState (the fnstate wrapper) to the user's element builder
|
|
544
562
|
current = bindContext.boundElementByKey[key] = renderNode(evaluateElement(bindContext.element, valueState))
|
|
545
563
|
current.key = key
|
|
546
564
|
}
|
|
565
|
+
|
|
547
566
|
// place the element in the parent
|
|
548
567
|
if (prev == null) {
|
|
549
568
|
if (!parent.lastChild || parent.lastChild.key !== current.key) {
|
|
@@ -560,9 +579,12 @@ function arrangeElements (ctx, bindContext, oldState) {
|
|
|
560
579
|
} else if (prev.previousSibling.key !== current.key) {
|
|
561
580
|
// the previous was deleted all together, so we will delete it and replace the element
|
|
562
581
|
if (keys[prev.previousSibling.key] === undefined) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
582
|
+
const keyToDelete = prev.previousSibling.key
|
|
583
|
+
delete bindContext.boundElementByKey[keyToDelete]
|
|
584
|
+
delete bindContext.elementStates[keyToDelete] // Cleanup element state
|
|
585
|
+
|
|
586
|
+
if (ctx.selectObservers[keyToDelete] !== undefined && current.insertAdjacentElement !== undefined) {
|
|
587
|
+
delete ctx.selectObservers[keyToDelete]
|
|
566
588
|
}
|
|
567
589
|
prev.previousSibling.replaceWith(current)
|
|
568
590
|
} else if (isNew) {
|
|
@@ -581,11 +603,13 @@ function arrangeElements (ctx, bindContext, oldState) {
|
|
|
581
603
|
prev = current
|
|
582
604
|
}
|
|
583
605
|
|
|
584
|
-
//
|
|
606
|
+
// 3. Catch any strays (Cleanup)
|
|
585
607
|
for (const key in bindContext.boundElementByKey) {
|
|
586
608
|
if (keys[key] === undefined) {
|
|
587
609
|
bindContext.boundElementByKey[key].remove()
|
|
588
610
|
delete bindContext.boundElementByKey[key]
|
|
611
|
+
delete bindContext.elementStates[key] // Cleanup element state
|
|
612
|
+
|
|
589
613
|
if (ctx.selectObservers[key] !== undefined) {
|
|
590
614
|
delete ctx.selectObservers[key]
|
|
591
615
|
}
|