@wcstack/state 1.22.5 → 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 +93 -4
- 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,6 +5322,31 @@ 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
5352
|
if (parentNode) {
|
|
@@ -5323,7 +5356,7 @@ class Content {
|
|
|
5323
5356
|
// 先頭ノードが末尾へ回転する。anchor を進めながら位置一致ノードを
|
|
5324
5357
|
// スキップすることで冪等にする(mutation record も発生させない)。
|
|
5325
5358
|
let anchor = targetNode;
|
|
5326
|
-
for (const node of this.
|
|
5359
|
+
for (const node of this._movableNodes()) {
|
|
5327
5360
|
if (anchor.nextSibling !== node) {
|
|
5328
5361
|
markObserverSkipOnAdd(node);
|
|
5329
5362
|
parentNode.insertBefore(node, anchor.nextSibling);
|
|
@@ -5390,6 +5423,53 @@ class Content {
|
|
|
5390
5423
|
this._mounted = false;
|
|
5391
5424
|
}
|
|
5392
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
|
+
}
|
|
5393
5473
|
/**
|
|
5394
5474
|
* SSR ハイドレーション用: 既存の DOM ノード配列から Content を生成する。
|
|
5395
5475
|
* テンプレートからの clone ではなく、SSR で描画済みのノードをそのまま使う。
|
|
@@ -5440,6 +5520,9 @@ function createPlanContent(bindingInfo, fragmentInfo, plan) {
|
|
|
5440
5520
|
}
|
|
5441
5521
|
}
|
|
5442
5522
|
const session = initializeRowBindings(plan, bindings);
|
|
5523
|
+
// プラン経路の content は範囲モードにならない: compileRowPlan は bindingType が
|
|
5524
|
+
// text / prop / event のもの以外(= for / if / elseif / else)を含む時点で不適格に
|
|
5525
|
+
// するため、プラン適格なフラグメントはトップレベル構造アンカーを持ち得ない。
|
|
5443
5526
|
const content = new Content(cloneFragment);
|
|
5444
5527
|
setBindingSessionByContent(content, session);
|
|
5445
5528
|
setBindingsByContent(content, bindings);
|
|
@@ -5456,6 +5539,8 @@ function createContent(bindingInfo) {
|
|
|
5456
5539
|
if (!fragmentInfo) {
|
|
5457
5540
|
raiseError(`Fragment with UUID "${bindingInfo.uuid}" not found.`);
|
|
5458
5541
|
}
|
|
5542
|
+
// SSR 描画中は行ごとの @@wcs-for-start/end がレンジの正本なので終端マーカーは付けない
|
|
5543
|
+
const ranged = !inSsr() && resolveRanged(fragmentInfo);
|
|
5459
5544
|
let plan = fragmentInfo.rowPlan;
|
|
5460
5545
|
if (typeof plan === 'undefined' || (plan !== null && plan.directional !== config.enableDirectionalInitialSync)) {
|
|
5461
5546
|
// 初回 or config(directional)が変わったときだけコンパイル。不適格は null を
|
|
@@ -5467,7 +5552,11 @@ function createContent(bindingInfo) {
|
|
|
5467
5552
|
}
|
|
5468
5553
|
const cloneFragment = document.importNode(fragmentInfo.fragment, true);
|
|
5469
5554
|
const initialInfo = initializeBindingsByFragment(cloneFragment, fragmentInfo.nodeInfos);
|
|
5470
|
-
|
|
5555
|
+
if (ranged) {
|
|
5556
|
+
// uuid は冒頭のガードで非 null が確定している(raiseError は never を返す)
|
|
5557
|
+
appendRowEndMarker(cloneFragment, bindingInfo.uuid);
|
|
5558
|
+
}
|
|
5559
|
+
const content = new Content(cloneFragment, ranged);
|
|
5471
5560
|
setBindingSessionByContent(content, initialInfo.bindingSession);
|
|
5472
5561
|
setBindingsByContent(content, initialInfo.bindingInfos);
|
|
5473
5562
|
const indexBindings = [];
|
|
@@ -6897,7 +6986,7 @@ async function buildBindings(root) {
|
|
|
6897
6986
|
}
|
|
6898
6987
|
}
|
|
6899
6988
|
|
|
6900
|
-
var version = "1.22.
|
|
6989
|
+
var version = "1.22.6";
|
|
6901
6990
|
var pkg = {
|
|
6902
6991
|
version: version};
|
|
6903
6992
|
|