@wcstack/state 1.22.4 → 1.22.6
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/index.esm.js +126 -36
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -5289,8 +5289,16 @@ class Content {
|
|
|
5289
5289
|
_firstNode = null;
|
|
5290
5290
|
_lastNode = null;
|
|
5291
5291
|
_mounted = false;
|
|
5292
|
-
|
|
5292
|
+
/**
|
|
5293
|
+
* 範囲モード。トップレベルに構造ディレクティブを持つ content でのみ true。
|
|
5294
|
+
* この content の実レンジは自分の childNodeArray より広い(ネストした
|
|
5295
|
+
* if/for が自分のアンカー直後に実ノードを挿すため)ので、移動は
|
|
5296
|
+
* firstNode..lastNode の DOM レンジで行う。
|
|
5297
|
+
*/
|
|
5298
|
+
_ranged = false;
|
|
5299
|
+
constructor(content, ranged = false) {
|
|
5293
5300
|
this._content = content;
|
|
5301
|
+
this._ranged = ranged;
|
|
5294
5302
|
this._childNodeArray = Array.from(this._content.childNodes);
|
|
5295
5303
|
this._firstNode = this._childNodeArray.length > 0 ? this._childNodeArray[0] : null;
|
|
5296
5304
|
this._lastNode = this._childNodeArray.length > 0 ? this._childNodeArray[this._childNodeArray.length - 1] : null;
|
|
@@ -5314,13 +5322,46 @@ class Content {
|
|
|
5314
5322
|
}
|
|
5315
5323
|
this._mounted = true;
|
|
5316
5324
|
}
|
|
5325
|
+
/**
|
|
5326
|
+
* 移動対象ノード列。通常は自分のトップレベルノードそのもの(同一参照を返すので
|
|
5327
|
+
* 追加アロケーション無し)。範囲モードでマウント中のときだけ、ネストした構造
|
|
5328
|
+
* ディレクティブが挿した実ノードを含む DOM レンジを収集する。
|
|
5329
|
+
*/
|
|
5330
|
+
_movableNodes() {
|
|
5331
|
+
if (!this._ranged || !this._mounted) {
|
|
5332
|
+
return this._childNodeArray;
|
|
5333
|
+
}
|
|
5334
|
+
const first = this._firstNode;
|
|
5335
|
+
const last = this._lastNode;
|
|
5336
|
+
if (first === null || last === null || first.parentNode === null) {
|
|
5337
|
+
return this._childNodeArray;
|
|
5338
|
+
}
|
|
5339
|
+
// 移動でsiblingが変わるため、先に列を確定させてから動かす
|
|
5340
|
+
const nodes = [];
|
|
5341
|
+
for (let node = first; node !== null; node = node.nextSibling) {
|
|
5342
|
+
nodes.push(node);
|
|
5343
|
+
if (node === last) {
|
|
5344
|
+
return nodes;
|
|
5345
|
+
}
|
|
5346
|
+
}
|
|
5347
|
+
// last へ到達しない(想定外の不連続)→ 従来どおり自分のノードだけ動かす
|
|
5348
|
+
return this._childNodeArray;
|
|
5349
|
+
}
|
|
5317
5350
|
mountAfter(targetNode) {
|
|
5318
5351
|
const parentNode = targetNode.parentNode;
|
|
5319
|
-
const nextSibling = targetNode.nextSibling;
|
|
5320
5352
|
if (parentNode) {
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5353
|
+
// マウント済み content にも再突入する(if の true→true 再適用・SSR
|
|
5354
|
+
// ハイドレーション産 content 等)。固定の nextSibling へ一括 insertBefore
|
|
5355
|
+
// すると、マウント済みでは nextSibling が自分の先頭ノードを指すため
|
|
5356
|
+
// 先頭ノードが末尾へ回転する。anchor を進めながら位置一致ノードを
|
|
5357
|
+
// スキップすることで冪等にする(mutation record も発生させない)。
|
|
5358
|
+
let anchor = targetNode;
|
|
5359
|
+
for (const node of this._movableNodes()) {
|
|
5360
|
+
if (anchor.nextSibling !== node) {
|
|
5361
|
+
markObserverSkipOnAdd(node);
|
|
5362
|
+
parentNode.insertBefore(node, anchor.nextSibling);
|
|
5363
|
+
}
|
|
5364
|
+
anchor = node;
|
|
5324
5365
|
}
|
|
5325
5366
|
}
|
|
5326
5367
|
this._mounted = true;
|
|
@@ -5382,6 +5423,53 @@ class Content {
|
|
|
5382
5423
|
this._mounted = false;
|
|
5383
5424
|
}
|
|
5384
5425
|
}
|
|
5426
|
+
/**
|
|
5427
|
+
* トップレベルに構造ディレクティブのプレースホルダを持つか。
|
|
5428
|
+
*
|
|
5429
|
+
* これを持つ content は、ネストした if/for が「自分のアンカー直後」に実ノードを
|
|
5430
|
+
* 挿すため、自分の childNodeArray が実レンジより狭くなる。その状態だと
|
|
5431
|
+
* (1) 呼び出し側の位置追跡(applyChangeToFor の lastNode)が実ノードの手前で
|
|
5432
|
+
* 止まり後続行が割り込む、(2) 移動時にネスト分を置き去りにする、の 2 つが起きる。
|
|
5433
|
+
* 該当テンプレートにだけ終端マーカーを持たせて実レンジを閉じる。
|
|
5434
|
+
*/
|
|
5435
|
+
function hasTopLevelStructural(fragment) {
|
|
5436
|
+
// config は setConfig で差し替わりうるので都度組む。テンプレート単位に一度しか
|
|
5437
|
+
// 走らない判定なので、この生成コストが行あたりに乗ることはない。
|
|
5438
|
+
const structural = new RegExp(`^@@(?:${config.commentForPrefix}|${config.commentIfPrefix}`
|
|
5439
|
+
+ `|${config.commentElseIfPrefix}|${config.commentElsePrefix}):`);
|
|
5440
|
+
for (let node = fragment.firstChild; node !== null; node = node.nextSibling) {
|
|
5441
|
+
if (node.nodeType !== Node.COMMENT_NODE) {
|
|
5442
|
+
continue;
|
|
5443
|
+
}
|
|
5444
|
+
// Comment の data は常に文字列(textContent の null 分岐を持ち込まない)
|
|
5445
|
+
if (structural.test(node.data)) {
|
|
5446
|
+
return true;
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
return false;
|
|
5450
|
+
}
|
|
5451
|
+
/**
|
|
5452
|
+
* 範囲モードの要否をテンプレート単位で一度だけ判定してキャッシュする。
|
|
5453
|
+
* 大多数のテンプレート(トップレベルが素の要素)は false を引くだけで、
|
|
5454
|
+
* 行ごとの追加コストはゼロ。
|
|
5455
|
+
*/
|
|
5456
|
+
function resolveRanged(fragmentInfo) {
|
|
5457
|
+
let ranged = fragmentInfo.topLevelStructural;
|
|
5458
|
+
if (typeof ranged === 'undefined') {
|
|
5459
|
+
ranged = fragmentInfo.topLevelStructural = hasTopLevelStructural(fragmentInfo.fragment);
|
|
5460
|
+
}
|
|
5461
|
+
return ranged;
|
|
5462
|
+
}
|
|
5463
|
+
const ROW_END_PREFIX = 'wcs-row-end';
|
|
5464
|
+
/**
|
|
5465
|
+
* 終端マーカーの付与。バインディング初期化の後に足すので nodePath 解決には影響しない
|
|
5466
|
+
* (末尾追加なので既存 index もずれない)。SSR 描画中は付けない — SSR は行ごとに
|
|
5467
|
+
* `@@wcs-for-start/end` を出力しており、そちらがレンジの正本かつハイドレーション
|
|
5468
|
+
* が読む対象なので、余計なコメントを混ぜない。
|
|
5469
|
+
*/
|
|
5470
|
+
function appendRowEndMarker(cloneFragment, uuid) {
|
|
5471
|
+
cloneFragment.appendChild(document.createComment(`${ROW_END_PREFIX}:${uuid}`));
|
|
5472
|
+
}
|
|
5385
5473
|
/**
|
|
5386
5474
|
* SSR ハイドレーション用: 既存の DOM ノード配列から Content を生成する。
|
|
5387
5475
|
* テンプレートからの clone ではなく、SSR で描画済みのノードをそのまま使う。
|
|
@@ -5432,6 +5520,9 @@ function createPlanContent(bindingInfo, fragmentInfo, plan) {
|
|
|
5432
5520
|
}
|
|
5433
5521
|
}
|
|
5434
5522
|
const session = initializeRowBindings(plan, bindings);
|
|
5523
|
+
// プラン経路の content は範囲モードにならない: compileRowPlan は bindingType が
|
|
5524
|
+
// text / prop / event のもの以外(= for / if / elseif / else)を含む時点で不適格に
|
|
5525
|
+
// するため、プラン適格なフラグメントはトップレベル構造アンカーを持ち得ない。
|
|
5435
5526
|
const content = new Content(cloneFragment);
|
|
5436
5527
|
setBindingSessionByContent(content, session);
|
|
5437
5528
|
setBindingsByContent(content, bindings);
|
|
@@ -5448,6 +5539,8 @@ function createContent(bindingInfo) {
|
|
|
5448
5539
|
if (!fragmentInfo) {
|
|
5449
5540
|
raiseError(`Fragment with UUID "${bindingInfo.uuid}" not found.`);
|
|
5450
5541
|
}
|
|
5542
|
+
// SSR 描画中は行ごとの @@wcs-for-start/end がレンジの正本なので終端マーカーは付けない
|
|
5543
|
+
const ranged = !inSsr() && resolveRanged(fragmentInfo);
|
|
5451
5544
|
let plan = fragmentInfo.rowPlan;
|
|
5452
5545
|
if (typeof plan === 'undefined' || (plan !== null && plan.directional !== config.enableDirectionalInitialSync)) {
|
|
5453
5546
|
// 初回 or config(directional)が変わったときだけコンパイル。不適格は null を
|
|
@@ -5459,7 +5552,11 @@ function createContent(bindingInfo) {
|
|
|
5459
5552
|
}
|
|
5460
5553
|
const cloneFragment = document.importNode(fragmentInfo.fragment, true);
|
|
5461
5554
|
const initialInfo = initializeBindingsByFragment(cloneFragment, fragmentInfo.nodeInfos);
|
|
5462
|
-
|
|
5555
|
+
if (ranged) {
|
|
5556
|
+
// uuid は冒頭のガードで非 null が確定している(raiseError は never を返す)
|
|
5557
|
+
appendRowEndMarker(cloneFragment, bindingInfo.uuid);
|
|
5558
|
+
}
|
|
5559
|
+
const content = new Content(cloneFragment, ranged);
|
|
5463
5560
|
setBindingSessionByContent(content, initialInfo.bindingSession);
|
|
5464
5561
|
setBindingsByContent(content, initialInfo.bindingInfos);
|
|
5465
5562
|
const indexBindings = [];
|
|
@@ -5728,12 +5825,10 @@ function applyChangeToFor(bindingInfo, context, newValue) {
|
|
|
5728
5825
|
}
|
|
5729
5826
|
}
|
|
5730
5827
|
|
|
5731
|
-
const lastConnectedByNode = new WeakMap();
|
|
5732
5828
|
function bindingInfoText(bindingInfo) {
|
|
5733
5829
|
return `${bindingInfo.bindingType} ${bindingInfo.statePathName} ${bindingInfo.outFilters.map(f => f.filterName).join('|')} ${bindingInfo.node.isConnected ? '(connected)' : '(disconnected)'}`;
|
|
5734
5830
|
}
|
|
5735
5831
|
function applyChangeToIf(bindingInfo, context, rawNewValue) {
|
|
5736
|
-
const currentConnected = bindingInfo.node.isConnected;
|
|
5737
5832
|
const newValue = Boolean(rawNewValue);
|
|
5738
5833
|
let content;
|
|
5739
5834
|
const contents = getContentSetByNode(bindingInfo.node);
|
|
@@ -5746,35 +5841,30 @@ function applyChangeToIf(bindingInfo, context, rawNewValue) {
|
|
|
5746
5841
|
const ssrMode = inSsr();
|
|
5747
5842
|
const uuid = bindingInfo.uuid ?? '';
|
|
5748
5843
|
const keyword = bindingInfo.bindingType; // if, elseif, else
|
|
5749
|
-
|
|
5750
|
-
if (
|
|
5751
|
-
if (
|
|
5752
|
-
console.log(`unmount if content : ${bindingInfoText(bindingInfo)}`);
|
|
5753
|
-
}
|
|
5754
|
-
deactivateContent(content);
|
|
5755
|
-
content.unmount();
|
|
5756
|
-
}
|
|
5757
|
-
if (newValue) {
|
|
5758
|
-
if (config.debug) {
|
|
5759
|
-
console.log(`mount if content : ${bindingInfoText(bindingInfo)}`);
|
|
5760
|
-
}
|
|
5761
|
-
if (ssrMode) {
|
|
5762
|
-
const startComment = document.createComment(`@@wcs-${keyword}-start:${uuid}:${bindingInfo.statePathName}`);
|
|
5763
|
-
bindingInfo.node.parentNode.insertBefore(startComment, bindingInfo.node.nextSibling);
|
|
5764
|
-
content.mountAfter(startComment);
|
|
5765
|
-
const endComment = document.createComment(`@@wcs-${keyword}-end:${uuid}:${bindingInfo.statePathName}`);
|
|
5766
|
-
const afterNode = content.lastNode ?? startComment;
|
|
5767
|
-
afterNode.parentNode.insertBefore(endComment, afterNode.nextSibling);
|
|
5768
|
-
}
|
|
5769
|
-
else {
|
|
5770
|
-
content.mountAfter(bindingInfo.node);
|
|
5771
|
-
}
|
|
5772
|
-
const loopContext = getLoopContextByNode(bindingInfo.node);
|
|
5773
|
-
activateContent(content, loopContext, context);
|
|
5844
|
+
if (!newValue) {
|
|
5845
|
+
if (config.debug) {
|
|
5846
|
+
console.log(`unmount if content : ${bindingInfoText(bindingInfo)}`);
|
|
5774
5847
|
}
|
|
5848
|
+
deactivateContent(content);
|
|
5849
|
+
content.unmount();
|
|
5775
5850
|
}
|
|
5776
|
-
|
|
5777
|
-
|
|
5851
|
+
if (newValue) {
|
|
5852
|
+
if (config.debug) {
|
|
5853
|
+
console.log(`mount if content : ${bindingInfoText(bindingInfo)}`);
|
|
5854
|
+
}
|
|
5855
|
+
if (ssrMode) {
|
|
5856
|
+
const startComment = document.createComment(`@@wcs-${keyword}-start:${uuid}:${bindingInfo.statePathName}`);
|
|
5857
|
+
bindingInfo.node.parentNode.insertBefore(startComment, bindingInfo.node.nextSibling);
|
|
5858
|
+
content.mountAfter(startComment);
|
|
5859
|
+
const endComment = document.createComment(`@@wcs-${keyword}-end:${uuid}:${bindingInfo.statePathName}`);
|
|
5860
|
+
const afterNode = content.lastNode ?? startComment;
|
|
5861
|
+
afterNode.parentNode.insertBefore(endComment, afterNode.nextSibling);
|
|
5862
|
+
}
|
|
5863
|
+
else {
|
|
5864
|
+
content.mountAfter(bindingInfo.node);
|
|
5865
|
+
}
|
|
5866
|
+
const loopContext = getLoopContextByNode(bindingInfo.node);
|
|
5867
|
+
activateContent(content, loopContext, context);
|
|
5778
5868
|
}
|
|
5779
5869
|
}
|
|
5780
5870
|
|
|
@@ -6896,7 +6986,7 @@ async function buildBindings(root) {
|
|
|
6896
6986
|
}
|
|
6897
6987
|
}
|
|
6898
6988
|
|
|
6899
|
-
var version = "1.22.
|
|
6989
|
+
var version = "1.22.6";
|
|
6900
6990
|
var pkg = {
|
|
6901
6991
|
version: version};
|
|
6902
6992
|
|