@wcstack/router 1.31.0 → 1.33.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/index.d.ts CHANGED
@@ -86,6 +86,13 @@ interface IRouteMatchResult {
86
86
  lastPath: string;
87
87
  }
88
88
  type GuardHandler = (toPath: string, fromPath: string) => boolean | Promise<boolean>;
89
+ interface _ILayout {
90
+ readonly uuid: string;
91
+ readonly enableShadowRoot: boolean;
92
+ readonly name: string;
93
+ loadTemplate(): Promise<HTMLTemplateElement>;
94
+ }
95
+ type ILayout = _ILayout & Pick<Element, 'childNodes'>;
89
96
  type SegmentType = 'static' | 'param' | 'catch-all';
90
97
  interface ISegmentInfo {
91
98
  type: SegmentType;
@@ -121,6 +128,8 @@ interface IRoute extends IRouteChildContainer {
121
128
  readonly absoluteSegmentCount: number;
122
129
  readonly segmentInfos: ISegmentInfo[];
123
130
  readonly absoluteSegmentInfos: ISegmentInfo[];
131
+ /** guard 属性の有無。SSR の guard バリア判定に使う(docs/ssr-router-design.md §2-4) */
132
+ readonly hasGuard: boolean;
124
133
  guardHandler: GuardHandler;
125
134
  shouldChange(newParams: Record<string, string>): boolean;
126
135
  guardCheck(matchResult: IRouteMatchResult): Promise<void>;
@@ -129,6 +138,23 @@ interface IRoute extends IRouteChildContainer {
129
138
  setParams(params: Record<string, string>, typedParams: Record<string, any>): void;
130
139
  clearParams(): void;
131
140
  notifyGuardHandlerLoadFailed(): void;
141
+ /**
142
+ * SSR ハイドレーションの採用: サーバー描画済みノード列を内容として引き取る
143
+ * (docs/ssr-router-design.md §4)
144
+ */
145
+ adoptChildNodes(nodes: Node[]): void;
146
+ }
147
+ /**
148
+ * Router 観測面のコミット 1 回分(docs/router-state-contract-design.md §3.4)。
149
+ */
150
+ interface IRouterCommit {
151
+ params: Record<string, string>;
152
+ typedParams: Record<string, any>;
153
+ routeName: string;
154
+ /** "?k=v" 形式または ""。パースは commit 側(Router)が行う */
155
+ search: string;
156
+ /** basename スライス後の path */
157
+ path: string;
132
158
  }
133
159
  interface IRouter extends IRouteChildContainer {
134
160
  readonly basename: string;
@@ -136,13 +162,49 @@ interface IRouter extends IRouteChildContainer {
136
162
  readonly template: HTMLTemplateElement;
137
163
  fallbackRoute: IRoute | null;
138
164
  path: string;
165
+ /** 現在マッチのマージ済み param(文字列・frozen)。fallback・初期化前は {} */
166
+ readonly params: Record<string, string>;
167
+ /** 同上の型変換済み値(frozen) */
168
+ readonly typedParams: Record<string, any>;
169
+ /** 現在 URL のクエリ(Record・last-wins・frozen)。クエリ無しは {} */
170
+ readonly searchParams: Record<string, string>;
171
+ /** 最深マッチルートの name 属性値。fallback 時は fallback ルートの name */
172
+ readonly routeName: string;
139
173
  navigate(path: string): Promise<void>;
174
+ /** navigateUrl(push)の対になる replace 遷移(§4.2) */
175
+ replace(path: string): Promise<void>;
176
+ /**
177
+ * same-match 判定(§4.4)。比較は basename スライス後の path 同士。
178
+ * 最初の成功 commit より前は常に false(初回ガード)。
179
+ */
180
+ isSameMatch(path: string): boolean;
181
+ /**
182
+ * 観測面のコミットと発火(§3.4)。全内部値を先にコミットし、その後で
183
+ * params → route-name → search → path の順に変化したものだけ発火する。
184
+ */
185
+ commitNavigation(commit: IRouterCommit): void;
186
+ /** `announce=` 用 live region。未生成なら null(docs/a11y-design.md §3-4) */
187
+ readonly a11yRegion: HTMLElement | null;
188
+ /** `<wcs-router focus=...>` の属性値(無ければ null) */
189
+ readonly focusPolicy: string | null;
190
+ /** `<wcs-router announce=...>` の属性値(無ければ null) */
191
+ readonly announcePolicy: string | null;
140
192
  }
141
193
  interface IOutlet {
142
194
  routesNode: IRouter;
143
195
  readonly rootNode: HTMLElement | ShadowRoot;
144
196
  lastRoutes: IRoute[];
145
197
  }
198
+ interface ILayoutOutlet {
199
+ layout: ILayout;
200
+ readonly name: string;
201
+ assignParams(params: Record<string, any>): void;
202
+ }
203
+ interface ILink {
204
+ readonly uuid: string;
205
+ readonly router: IRouter;
206
+ readonly anchorElement: HTMLAnchorElement | null;
207
+ }
146
208
 
147
209
  /**
148
210
  * AppRoutes - Root component for @wcstack/router
@@ -150,6 +212,12 @@ interface IOutlet {
150
212
  * Container element that manages route definitions and navigation.
151
213
  */
152
214
  declare class Router extends HTMLElement implements IRouter {
215
+ /**
216
+ * @wcstack/server の待機プロトコル(docs/ssr-router-design.md §3.2)。
217
+ * renderToString はこのフラグを持つ要素の connectedCallbackPromise を待って
218
+ * からシリアライズする — 初期ルート適用の完了がサーバー出力に反映される。
219
+ */
220
+ static hasConnectedCallbackPromise: boolean;
153
221
  static wcBindable: IWcBindable;
154
222
  private _outlet;
155
223
  private _template;
@@ -161,9 +229,35 @@ declare class Router extends HTMLElement implements IRouter {
161
229
  private _listeningPopState;
162
230
  private _listeningNavigate;
163
231
  private _navigateUrl;
232
+ private _replaceUrl;
164
233
  private _disconnectedDuringInit;
165
234
  private _initializing;
235
+ private _a11yRegion;
236
+ private _params;
237
+ private _typedParams;
238
+ private _searchParams;
239
+ private _routeName;
240
+ /** 最初の成功 commit を通過したか(§4.4 の初回ガード) */
241
+ private _hasCommitted;
242
+ private _connectedCallbackPromise;
243
+ private _resolveConnectedCallback;
244
+ private _rejectConnectedCallback;
166
245
  constructor();
246
+ get connectedCallbackPromise(): Promise<void>;
247
+ get a11yRegion(): HTMLElement | null;
248
+ get focusPolicy(): string | null;
249
+ get announcePolicy(): string | null;
250
+ /**
251
+ * `announce=` 用 live region を <wcs-router> 直下に空のまま用意する
252
+ * (docs/a11y-design.md §3-4)。
253
+ * - 告知より**前**から DOM に居ないと SR に読まれないため、announce 時の
254
+ * 遅延生成はできない。
255
+ * - outlet 配下はナビゲーションごとに破棄され、オプトインで shadow root にも
256
+ * なる。document.body 直下は router の寿命を超えて漏れ、マルチ router で
257
+ * 競合する。よって配置は <wcs-router> 直下の一択。
258
+ * - display:none は live region を殺すため、sr-only クリップで隠す。
259
+ */
260
+ private _ensureA11yRegion;
167
261
  /**
168
262
  * Normalize a URL pathname to a route path.
169
263
  * 共通実装は normalizePathname.ts を参照(Link との挙動整合のため)。
@@ -188,6 +282,32 @@ declare class Router extends HTMLElement implements IRouter {
188
282
  * applyRoute 内で設定される値です。
189
283
  */
190
284
  set path(value: string);
285
+ get params(): Record<string, string>;
286
+ get typedParams(): Record<string, any>;
287
+ get searchParams(): Record<string, string>;
288
+ get routeName(): string;
289
+ /**
290
+ * same-match 判定(docs/router-state-contract-design.md §4.4)。
291
+ *
292
+ * 比較は **basename スライス後の path 同士**(`_path` はスライス後で保存済み)。
293
+ * 判定が必要な地点は 2 箇所 — `_onNavigateFunc` の intercept オプション決定時と
294
+ * `applyRoute` の入口分岐 — で、両方がこの単一実装を呼ぶ。
295
+ *
296
+ * 初回ガード: 最初の成功 commit より前には適用しない。初期 `_path = ""` が
297
+ * 正規化後パス(常に `/` 始まり)と一致しないため偶然安全だが、
298
+ * normalizePathname の実装詳細に依存させず規範として明示する。
299
+ */
300
+ isSameMatch(path: string): boolean;
301
+ /**
302
+ * 観測面のコミットと発火(docs/router-state-contract-design.md §3.4)。
303
+ *
304
+ * 全内部値を先にコミットし、その後で初めてイベントを発火する — どのイベントの
305
+ * リスナーから要素プロパティを読んでも、遷移後スナップショットの一貫した値が
306
+ * 見える。発火順序は params → route-name → search → path。`path` を最後に
307
+ * 置くのは、既存例で `path` が「ナビゲーション完了」の信号として使われている
308
+ * ため。各イベントは変化した commit のみ発火する。
309
+ */
310
+ commitNavigation(commit: IRouterCommit): void;
191
311
  get fallbackRoute(): IRoute | null;
192
312
  /**
193
313
  * Routeのfallback属性がある場合にそのルートを設定します。
@@ -195,7 +315,21 @@ declare class Router extends HTMLElement implements IRouter {
195
315
  set fallbackRoute(value: IRoute | null);
196
316
  get navigateUrl(): string | null;
197
317
  set navigateUrl(value: string | null);
318
+ get replaceUrl(): string | null;
319
+ /**
320
+ * navigateUrl と完全同型の null-idle transient(docs/router-state-contract-design.md §4.2)。
321
+ * null は待機・書き込みで replace() を起動・完了で自己リセットして
322
+ * `wcs-router:replace-url-changed`(detail: null)を発火する。
323
+ */
324
+ set replaceUrl(value: string | null);
198
325
  navigate(path: string): Promise<void>;
326
+ /**
327
+ * navigateUrl(push)の対になる replace 遷移(docs/router-state-contract-design.md §4.2)。
328
+ * Navigation API では `navigation.navigate(url, { history: "replace" })`、
329
+ * フォールバックでは `history.replaceState` + applyRoute + 通知。
330
+ */
331
+ replace(path: string): Promise<void>;
332
+ private _performNavigation;
199
333
  /**
200
334
  * basename 配下の URL かどうかを判定する。
201
335
  * basename が空の場合はすべての URL にマッチする。
@@ -205,12 +339,38 @@ declare class Router extends HTMLElement implements IRouter {
205
339
  private _onNavigate;
206
340
  private _onPopState;
207
341
  private _initialize;
342
+ /**
343
+ * サーバー描画済み outlet の採用(docs/ssr-router-design.md §4)。
344
+ *
345
+ * 検証(一意な absolutePath・マーカーの整合・現在 URL のマッチとの一致)を
346
+ * **すべて DOM 変更の前に**行い、途中で断念しても半採用状態を残さない。
347
+ * 成立すれば DOM 変更ゼロで「すでにナビゲート済み」の状態を確立する —
348
+ * state がハイドレートしたバインディングは採用ノード上で生きたままになる。
349
+ *
350
+ * @returns 採用が成立した場合 true。false は呼び出し側(_initialize)が
351
+ * サーバー DOM を破棄して従来描画にフォールバックする。
352
+ */
353
+ private _hydrateFromSsr;
354
+ /**
355
+ * SSR モードの初期ルート描画(docs/ssr-router-design.md §3.2)。
356
+ * 初回描画は transition arbiter に渡らない既存規則(showRouteContent)により
357
+ * 常に同期適用される。navigate / popstate リスナ・a11y region・
358
+ * `wcs:navigate` 通知はサーバーでは不要(connectedCallback 側で登録しない)。
359
+ */
360
+ private _renderForSsr;
361
+ /**
362
+ * 初期表示ルートの内容を binder プロトコルへ差し出す。SSR 描画(_renderForSsr)と
363
+ * ハイドレーション不能時の描き直し(state が先にハイドレートを終えている可能性が
364
+ * ある)の両方から呼ぶ。bind() は冪等なので余分に差し出しても壊れない。
365
+ */
366
+ private _offerInitialContentToBinder;
367
+ /** ルートツリー全体(ネスト含む)への走査 */
368
+ private _forEachRoute;
208
369
  connectedCallback(): Promise<void>;
209
370
  disconnectedCallback(): void;
210
371
  }
211
372
 
212
373
  declare class Route extends HTMLElement implements IRoute {
213
- static wcBindable: IWcBindable;
214
374
  private _core;
215
375
  private _routeParentNode;
216
376
  private _routeChildNodes;
@@ -228,6 +388,13 @@ declare class Route extends HTMLElement implements IRoute {
228
388
  get uuid(): string;
229
389
  get placeHolder(): Comment;
230
390
  get childNodeArray(): Node[];
391
+ /**
392
+ * SSR ハイドレーションの採用(docs/ssr-router-design.md §4)。
393
+ * サーバー描画済みの DOM ノード列をこのルートの内容として引き取る。
394
+ * 以後の hideRoute / showRoute は採用ノードに対して従来どおり動く。
395
+ * template 由来の fresh クローン(自身の childNodes)は不要になるため破棄する。
396
+ */
397
+ adoptChildNodes(nodes: Node[]): void;
231
398
  get routes(): IRoute[];
232
399
  get childIndex(): number;
233
400
  get path(): string;
@@ -245,6 +412,7 @@ declare class Route extends HTMLElement implements IRoute {
245
412
  get segmentCount(): number;
246
413
  get absoluteSegmentCount(): number;
247
414
  get fullpath(): string;
415
+ get hasGuard(): boolean;
248
416
  get guardHandler(): GuardHandler;
249
417
  set guardHandler(value: GuardHandler);
250
418
  setParams(params: Record<string, string>, typedParams: Record<string, any>): void;
@@ -271,8 +439,21 @@ interface RouteParseOptions {
271
439
  guardFallback?: string | null;
272
440
  name?: string;
273
441
  }
442
+ /**
443
+ * NOTE: RouteCore / Route は `static wcBindable` を**宣言しない**
444
+ * (docs/router-state-contract-design.md §5.1 / D2)。
445
+ *
446
+ * `<wcs-route>` は parse 時に clone された detached コントローラであり、live DOM に
447
+ * 入るのは placeholder コメントとスタンプされた子ノードだけ。data-wcs は live DOM
448
+ * 上の属性走査で結線する仕組みなので、宣言しても構造的に到達不能な「果たせない
449
+ * 約束」になる。params / typedParams / routeName の観測面は live DOM に居る
450
+ * `<wcs-router>` に集約した(Router.wcBindable)。
451
+ *
452
+ * `wcs-route:params-changed` / `wcs-route:active-changed` の dispatch は存置する —
453
+ * RouteCore は EventTarget であり、Core 直接消費(signals の正式推奨形)と
454
+ * ユニットテストの観測面として生きている。
455
+ */
274
456
  declare class RouteCore extends EventTarget {
275
- static wcBindable: IWcBindable;
276
457
  private _target;
277
458
  private _parentCore;
278
459
  private _path;
@@ -318,6 +499,12 @@ declare class RouteCore extends EventTarget {
318
499
  setParams(params: Record<string, string>, typedParams: Record<string, any>): void;
319
500
  clearParams(): void;
320
501
  shouldChange(newParams: Record<string, string>): boolean;
502
+ /**
503
+ * guard 属性の有無(parsePath の options.hasGuard)。SSR の guard バリア
504
+ * — guard 付きルートはサーバーで描かない(docs/ssr-router-design.md §2-4)—
505
+ * がハンドラのロードを待たずに判定するために使う。
506
+ */
507
+ get hasGuard(): boolean;
321
508
  get guardHandler(): GuardHandler;
322
509
  set guardHandler(value: GuardHandler);
323
510
  /**
@@ -330,5 +517,163 @@ declare class RouteCore extends EventTarget {
330
517
 
331
518
  declare const VERSION: string;
332
519
 
520
+ declare class Outlet extends HTMLElement implements IOutlet {
521
+ private _routesNode;
522
+ private _lastRoutes;
523
+ private _initialized;
524
+ constructor();
525
+ get routesNode(): IRouter;
526
+ set routesNode(value: IRouter);
527
+ get rootNode(): HTMLElement | ShadowRoot;
528
+ get lastRoutes(): IRoute[];
529
+ set lastRoutes(value: IRoute[]);
530
+ /**
531
+ * shadowRoot 有効化判定。Layout と挙動を揃え、属性で個別オーバーライド可能にする。
532
+ * - `enable-shadow-root` 属性あり → true
533
+ * - `disable-shadow-root` 属性あり → false
534
+ * - いずれもなし → config.enableShadowRoot を尊重
535
+ */
536
+ private _resolveEnableShadowRoot;
537
+ private _initialize;
538
+ connectedCallback(): void;
539
+ /**
540
+ * Outlet が disconnect された際の状態クリーンアップ。
541
+ *
542
+ * `_lastRoutes` をクリアすることで、再接続後の applyRoute における diff
543
+ * (既に show 済みのルートは show を skip する判定)が、切断中に外部から
544
+ * 操作された DOM と整合しなくなる事故を防ぐ。
545
+ *
546
+ * 仕様前提として Outlet は Router と一体運用される(Router が `_getOutlet()` で
547
+ * 自身の兄弟に Outlet を配置・参照する)。それでも単独で再接続される
548
+ * エッジケースに備える防衛的措置として `_lastRoutes` のみクリアする。
549
+ * `_initialized` と shadowRoot は維持し、再 attachShadow による
550
+ * InvalidStateError を回避する。
551
+ */
552
+ disconnectedCallback(): void;
553
+ }
554
+
555
+ declare class Layout extends HTMLElement implements ILayout {
556
+ private _uuid;
557
+ constructor();
558
+ private _loadTemplateFromSource;
559
+ private _loadTemplateFromDocument;
560
+ loadTemplate(): Promise<HTMLTemplateElement>;
561
+ get uuid(): string;
562
+ get enableShadowRoot(): boolean;
563
+ get name(): string;
564
+ }
565
+
566
+ declare class LayoutOutlet extends HTMLElement implements ILayoutOutlet {
567
+ private _layout;
568
+ private _initialized;
569
+ private _initializing;
570
+ private _disconnectedDuringInit;
571
+ private _layoutChildNodes;
572
+ constructor();
573
+ get layout(): ILayout;
574
+ set layout(value: ILayout);
575
+ get name(): string;
576
+ private _initialize;
577
+ connectedCallback(): Promise<void>;
578
+ disconnectedCallback(): void;
579
+ assignParams(params: Record<string, any>): void;
580
+ }
581
+
582
+ declare class Link extends HTMLElement implements ILink {
583
+ static get observedAttributes(): string[];
584
+ private _childNodeArray;
585
+ private _uuid;
586
+ private _path;
587
+ private _router;
588
+ private _anchorElement;
589
+ private _initialized;
590
+ private _onClick?;
591
+ constructor();
592
+ get uuid(): string;
593
+ /**
594
+ * 最寄りの Router を返す。
595
+ *
596
+ * 注意: この getter は DOM 走査で Router を探すため、
597
+ * Router がまだ upgrade されていない場合は HTMLElement として返る可能性がある。
598
+ * 通常は registerComponents() で Router を Link より先に upgrade することを推奨する。
599
+ */
600
+ get router(): Router;
601
+ private _initialize;
602
+ /**
603
+ * URL pathname を正規化する。Router と共通実装を使うことで
604
+ * basenameFileExtensions の取り扱いを揃え、active 判定の取りこぼしを防ぐ。
605
+ */
606
+ private _normalizePathname;
607
+ private _joinInternalPath;
608
+ /**
609
+ * router が扱う内部ターゲットか。`/` 始まりに加え、`?` 始まり(クエリのみ遷移 —
610
+ * docs/router-state-contract-design.md §4.1)も内部ターゲットとして受理する。
611
+ */
612
+ private _isInternalTarget;
613
+ private _setAnchorHref;
614
+ connectedCallback(): void;
615
+ /**
616
+ * サーバーが生成した目印付き anchor(直後の兄弟)。クライアントの採用対象
617
+ */
618
+ private _findSsrAnchor;
619
+ private _connect;
620
+ disconnectedCallback(): void;
621
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
622
+ private _updateActiveState;
623
+ get anchorElement(): HTMLAnchorElement | null;
624
+ }
625
+
626
+ declare class Head extends HTMLElement {
627
+ private _initialized;
628
+ private _childElementArray;
629
+ constructor();
630
+ private _initialize;
631
+ connectedCallback(): void;
632
+ disconnectedCallback(): void;
633
+ get childElementArray(): Element[];
634
+ /**
635
+ * 要素の一意キーを生成(WeakMap でキャッシュ)
636
+ */
637
+ private _getKey;
638
+ /**
639
+ * 要素の一意キーを計算(実体)
640
+ */
641
+ private _computeKey;
642
+ /**
643
+ * head 内の要素を key で引ける Map を構築する。
644
+ * `_reapplyHead` のループ前に一度だけ呼び出し、O(N) lookup に置き換えるためのヘルパ。
645
+ *
646
+ * 設計仕様: 同一 key の要素が複数 `document.head` 内に存在する場合は **first-wins**
647
+ * (DOM 順で最初の要素のみ採用)。これは `_captureInitialHead` および
648
+ * `initialHeadValues` の挙動とも整合する。
649
+ * 重複は基本的にユーザーの記述ミスだが、_getKey の粒度(href/name 等の主要属性のみ)に
650
+ * よる「論理的重複」もあり得るため、サイレントに first-wins とする。
651
+ * 厳密な重複検出が必要な場合は呼び出し側で行う。
652
+ */
653
+ private _buildHeadElementMap;
654
+ /**
655
+ * 初期の<head>状態をキャプチャ
656
+ * document.head内の全ての要素をスキャンして保存する
657
+ */
658
+ private _captureInitialHead;
659
+ /**
660
+ * スタック全体からheadを再構築
661
+ * 後のHeadが優先される(上書き)
662
+ */
663
+ private _reapplyHead;
664
+ }
665
+
666
+ declare global {
667
+ interface HTMLElementTagNameMap {
668
+ "wcs-router": Router;
669
+ "wcs-route": Route;
670
+ "wcs-outlet": Outlet;
671
+ "wcs-layout": Layout;
672
+ "wcs-layout-outlet": LayoutOutlet;
673
+ "wcs-link": Link;
674
+ "wcs-head": Head;
675
+ }
676
+ }
677
+
333
678
  export { Route, RouteCore, Router, VERSION, bootstrapRouter, getConfig };
334
679
  export type { IWritableConfig, IWritableTagNames, RouteParseOptions };