@aiquants/virtualscroll 3.6.1 → 3.7.1

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.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @module labels
3
+ * @description Built-in UI chrome label catalog of the package. Covers exactly the seven strings
4
+ * the components render on their own: the ScrollBar arrow aria-labels, the VirtualScroll
5
+ * scroll-to-edge pill texts and the empty-state text. Live-region wording stays consumer-owned
6
+ * (`liveRegion.format` / `liveRegion.buildMessage`) and is not part of this catalog. The default
7
+ * locale is `"en"`; `"ja"` is the second locale. No language negotiation happens here: hosts map
8
+ * `navigator.language` (or anything else) to a supported locale themselves.
9
+ *
10
+ * @description パッケージ内蔵の UI クローム文言カタログ。コンポーネント自身が描画する 7 文言
11
+ * (ScrollBar 矢印の aria-label、VirtualScroll の端スクロールピル文言、空状態文言) だけを対象とし、
12
+ * ライブリージョンの文言は利用側の所有 (`liveRegion.format` / `liveRegion.buildMessage`) で
13
+ * 本カタログの対象外。既定ロケールは `"en"`、第 2 ロケールは `"ja"`。言語ネゴシエーションは行わず、
14
+ * `navigator.language` 等から対応ロケールへの対応付けはホスト側の責務。
15
+ */
16
+ /**
17
+ * Supported UI chrome locales, in declaration order. The first entry is NOT implicitly the
18
+ * default — the default lives only in {@link resolveVirtualScrollLocale}.
19
+ * 対応する UI クロームロケールの一覧 (宣言順)。先頭要素が暗黙の既定値になるわけではなく、
20
+ * 既定値は {@link resolveVirtualScrollLocale} にのみ存在。
21
+ */
22
+ export declare const VIRTUAL_SCROLL_LOCALES: readonly ["en", "ja"];
23
+ /**
24
+ * A supported UI chrome locale (`"en"` | `"ja"`).
25
+ * 対応 UI クロームロケール (`"en"` | `"ja"`)。
26
+ */
27
+ export type VirtualScrollLocale = (typeof VIRTUAL_SCROLL_LOCALES)[number];
28
+ /**
29
+ * The complete set of built-in chrome strings, one value per rendered surface.
30
+ * 内蔵クローム文言の完全な集合 (描画面ごとに 1 値)。
31
+ */
32
+ export type VirtualScrollLabels = {
33
+ /**
34
+ * aria-label of the vertical ScrollBar start (up) arrow button.
35
+ * 縦 ScrollBar 始端 (上) 矢印ボタンの aria-label。
36
+ */
37
+ readonly scrollUp: string;
38
+ /**
39
+ * aria-label of the vertical ScrollBar end (down) arrow button.
40
+ * 縦 ScrollBar 終端 (下) 矢印ボタンの aria-label。
41
+ */
42
+ readonly scrollDown: string;
43
+ /**
44
+ * aria-label of the horizontal ScrollBar start (left) arrow button.
45
+ * 横 ScrollBar 始端 (左) 矢印ボタンの aria-label。
46
+ */
47
+ readonly scrollLeft: string;
48
+ /**
49
+ * aria-label of the horizontal ScrollBar end (right) arrow button.
50
+ * 横 ScrollBar 終端 (右) 矢印ボタンの aria-label。
51
+ */
52
+ readonly scrollRight: string;
53
+ /**
54
+ * Text of the VirtualScroll scroll-to-top pill, shown when
55
+ * `scrollBarOptions.enableScrollToTopBottomButtons` is on.
56
+ * `scrollBarOptions.enableScrollToTopBottomButtons` 有効時に表示される VirtualScroll 先頭移動ピルの文言。
57
+ */
58
+ readonly scrollToTop: string;
59
+ /**
60
+ * Text of the VirtualScroll scroll-to-bottom pill, shown when
61
+ * `scrollBarOptions.enableScrollToTopBottomButtons` is on.
62
+ * `scrollBarOptions.enableScrollToTopBottomButtons` 有効時に表示される VirtualScroll 末尾移動ピルの文言。
63
+ */
64
+ readonly scrollToBottom: string;
65
+ /**
66
+ * VirtualScroll empty-state text shown when `itemCount === 0`. VirtualGrid shows it too, for
67
+ * 0 rows, an all-frozen row set and degenerate bands (its embedded VirtualScroll gets 0 items).
68
+ * `itemCount === 0` 時の VirtualScroll 空状態文言。VirtualGrid も 0 行・全行固定・退化帯で表示
69
+ * (内蔵 VirtualScroll の項目数が 0 になるため)。
70
+ */
71
+ readonly noItems: string;
72
+ };
73
+ /**
74
+ * Partial per-key overrides laid over the catalog of the chosen locale. An `undefined` value keeps
75
+ * the catalog value; any present value must be a string with non-whitespace content.
76
+ * 選択ロケールのカタログへ重ねるキー単位の部分上書き。`undefined` 値はカタログ値を維持し、
77
+ * 値を与える場合は空白以外の文字を含む文字列であることが必須。
78
+ */
79
+ export type VirtualScrollLabelOverrides = {
80
+ readonly [K in keyof VirtualScrollLabels]?: VirtualScrollLabels[K];
81
+ };
82
+ /**
83
+ * Every key of {@link VirtualScrollLabels}, in catalog order. This is the closed key set that
84
+ * overrides are validated against.
85
+ * {@link VirtualScrollLabels} の全キー (カタログ順)。上書き検証に用いる閉じたキー集合。
86
+ */
87
+ export declare const VIRTUAL_SCROLL_LABEL_KEYS: readonly ["scrollUp", "scrollDown", "scrollLeft", "scrollRight", "scrollToTop", "scrollToBottom", "noItems"];
88
+ /**
89
+ * Frozen built-in catalogs per locale. `en` is the package's historical English wording.
90
+ * ロケールごとの凍結済み内蔵カタログ。`en` はパッケージ従来の英語文言。
91
+ */
92
+ export declare const VIRTUAL_SCROLL_LABEL_CATALOGS: Readonly<Record<VirtualScrollLocale, VirtualScrollLabels>>;
93
+ /**
94
+ * Resolves the UI chrome locale. `undefined` (an absent prop) maps to the default `"en"`; a member
95
+ * of {@link VIRTUAL_SCROLL_LOCALES} is returned as-is. This is the single place the default lives.
96
+ * UI クロームロケールの解決。`undefined` (prop 未指定) は既定の `"en"`、
97
+ * {@link VIRTUAL_SCROLL_LOCALES} の要素はそのまま返却。既定値を持つ唯一の場所。
98
+ *
99
+ * @param locale - Requested locale, or `undefined` for the default / 要求ロケール (`undefined` で既定)
100
+ * @returns The resolved supported locale / 解決済みの対応ロケール
101
+ * @throws {RangeError} When `locale` is neither `undefined` nor a supported locale (`null`, `""`,
102
+ * `"EN"`, `"ja-JP"`, `"fr"`, numbers, ...) — no language negotiation /
103
+ * `undefined` でも対応ロケールでもない場合 (`null`、`""`、`"EN"`、`"ja-JP"`、`"fr"`、数値など)。言語ネゴシエーションなし
104
+ */
105
+ export declare const resolveVirtualScrollLocale: (locale: VirtualScrollLocale | undefined) => VirtualScrollLocale;
106
+ /**
107
+ * Resolves the effective labels: the catalog of the resolved locale overlaid by `overrides`.
108
+ * Returns the frozen catalog itself (same identity) when `overrides` is `undefined`, otherwise a
109
+ * new frozen object. Inputs are never mutated.
110
+ * 実効ラベルの解決。解決済みロケールのカタログへ `overrides` を重ねた結果。`overrides` が
111
+ * `undefined` なら凍結カタログそのもの (同一参照)、それ以外は新しい凍結オブジェクトを返却。入力は不変。
112
+ *
113
+ * @param locale - Requested locale, or `undefined` for the default / 要求ロケール (`undefined` で既定)
114
+ * @param overrides - Per-key overrides, or `undefined` for none / キー単位の上書き (`undefined` で上書きなし)
115
+ * @returns The resolved, frozen labels / 解決済みの凍結ラベル
116
+ * @throws {RangeError} When the locale is unsupported, `overrides` is `null` or not an object,
117
+ * `overrides` is not a plain object (its prototype is neither `Object.prototype` nor `null`, e.g.
118
+ * an array or a class instance), an own key is not a label key, or a present own value is not a
119
+ * string with non-whitespace content. Only own properties are read /
120
+ * ロケールが非対応、`overrides` が `null` または非オブジェクト、`overrides` が素のオブジェクトでない
121
+ * (プロトタイプが `Object.prototype` でも `null` でもない。配列やクラスインスタンスなど)、自身のキーが
122
+ * ラベルキー外、または与えられた自身の値が空白以外の文字を含む文字列でない場合。読むのは自身の
123
+ * プロパティのみ
124
+ */
125
+ export declare const resolveVirtualScrollLabels: (locale: VirtualScrollLocale | undefined, overrides: VirtualScrollLabelOverrides | undefined) => VirtualScrollLabels;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @module labels
3
+ * @description Built-in UI chrome label catalog of the package. Covers exactly the seven strings
4
+ * the components render on their own: the ScrollBar arrow aria-labels, the VirtualScroll
5
+ * scroll-to-edge pill texts and the empty-state text. Live-region wording stays consumer-owned
6
+ * (`liveRegion.format` / `liveRegion.buildMessage`) and is not part of this catalog. The default
7
+ * locale is `"en"`; `"ja"` is the second locale. No language negotiation happens here: hosts map
8
+ * `navigator.language` (or anything else) to a supported locale themselves.
9
+ *
10
+ * @description パッケージ内蔵の UI クローム文言カタログ。コンポーネント自身が描画する 7 文言
11
+ * (ScrollBar 矢印の aria-label、VirtualScroll の端スクロールピル文言、空状態文言) だけを対象とし、
12
+ * ライブリージョンの文言は利用側の所有 (`liveRegion.format` / `liveRegion.buildMessage`) で
13
+ * 本カタログの対象外。既定ロケールは `"en"`、第 2 ロケールは `"ja"`。言語ネゴシエーションは行わず、
14
+ * `navigator.language` 等から対応ロケールへの対応付けはホスト側の責務。
15
+ */
16
+ /**
17
+ * Supported UI chrome locales, in declaration order. The first entry is NOT implicitly the
18
+ * default — the default lives only in {@link resolveVirtualScrollLocale}.
19
+ * 対応する UI クロームロケールの一覧 (宣言順)。先頭要素が暗黙の既定値になるわけではなく、
20
+ * 既定値は {@link resolveVirtualScrollLocale} にのみ存在。
21
+ */
22
+ export declare const VIRTUAL_SCROLL_LOCALES: readonly ["en", "ja"];
23
+ /**
24
+ * A supported UI chrome locale (`"en"` | `"ja"`).
25
+ * 対応 UI クロームロケール (`"en"` | `"ja"`)。
26
+ */
27
+ export type VirtualScrollLocale = (typeof VIRTUAL_SCROLL_LOCALES)[number];
28
+ /**
29
+ * The complete set of built-in chrome strings, one value per rendered surface.
30
+ * 内蔵クローム文言の完全な集合 (描画面ごとに 1 値)。
31
+ */
32
+ export type VirtualScrollLabels = {
33
+ /**
34
+ * aria-label of the vertical ScrollBar start (up) arrow button.
35
+ * 縦 ScrollBar 始端 (上) 矢印ボタンの aria-label。
36
+ */
37
+ readonly scrollUp: string;
38
+ /**
39
+ * aria-label of the vertical ScrollBar end (down) arrow button.
40
+ * 縦 ScrollBar 終端 (下) 矢印ボタンの aria-label。
41
+ */
42
+ readonly scrollDown: string;
43
+ /**
44
+ * aria-label of the horizontal ScrollBar start (left) arrow button.
45
+ * 横 ScrollBar 始端 (左) 矢印ボタンの aria-label。
46
+ */
47
+ readonly scrollLeft: string;
48
+ /**
49
+ * aria-label of the horizontal ScrollBar end (right) arrow button.
50
+ * 横 ScrollBar 終端 (右) 矢印ボタンの aria-label。
51
+ */
52
+ readonly scrollRight: string;
53
+ /**
54
+ * Text of the VirtualScroll scroll-to-top pill, shown when
55
+ * `scrollBarOptions.enableScrollToTopBottomButtons` is on.
56
+ * `scrollBarOptions.enableScrollToTopBottomButtons` 有効時に表示される VirtualScroll 先頭移動ピルの文言。
57
+ */
58
+ readonly scrollToTop: string;
59
+ /**
60
+ * Text of the VirtualScroll scroll-to-bottom pill, shown when
61
+ * `scrollBarOptions.enableScrollToTopBottomButtons` is on.
62
+ * `scrollBarOptions.enableScrollToTopBottomButtons` 有効時に表示される VirtualScroll 末尾移動ピルの文言。
63
+ */
64
+ readonly scrollToBottom: string;
65
+ /**
66
+ * VirtualScroll empty-state text shown when `itemCount === 0`. VirtualGrid shows it too, for
67
+ * 0 rows, an all-frozen row set and degenerate bands (its embedded VirtualScroll gets 0 items).
68
+ * `itemCount === 0` 時の VirtualScroll 空状態文言。VirtualGrid も 0 行・全行固定・退化帯で表示
69
+ * (内蔵 VirtualScroll の項目数が 0 になるため)。
70
+ */
71
+ readonly noItems: string;
72
+ };
73
+ /**
74
+ * Partial per-key overrides laid over the catalog of the chosen locale. An `undefined` value keeps
75
+ * the catalog value; any present value must be a string with non-whitespace content.
76
+ * 選択ロケールのカタログへ重ねるキー単位の部分上書き。`undefined` 値はカタログ値を維持し、
77
+ * 値を与える場合は空白以外の文字を含む文字列であることが必須。
78
+ */
79
+ export type VirtualScrollLabelOverrides = {
80
+ readonly [K in keyof VirtualScrollLabels]?: VirtualScrollLabels[K];
81
+ };
82
+ /**
83
+ * Every key of {@link VirtualScrollLabels}, in catalog order. This is the closed key set that
84
+ * overrides are validated against.
85
+ * {@link VirtualScrollLabels} の全キー (カタログ順)。上書き検証に用いる閉じたキー集合。
86
+ */
87
+ export declare const VIRTUAL_SCROLL_LABEL_KEYS: readonly ["scrollUp", "scrollDown", "scrollLeft", "scrollRight", "scrollToTop", "scrollToBottom", "noItems"];
88
+ /**
89
+ * Frozen built-in catalogs per locale. `en` is the package's historical English wording.
90
+ * ロケールごとの凍結済み内蔵カタログ。`en` はパッケージ従来の英語文言。
91
+ */
92
+ export declare const VIRTUAL_SCROLL_LABEL_CATALOGS: Readonly<Record<VirtualScrollLocale, VirtualScrollLabels>>;
93
+ /**
94
+ * Resolves the UI chrome locale. `undefined` (an absent prop) maps to the default `"en"`; a member
95
+ * of {@link VIRTUAL_SCROLL_LOCALES} is returned as-is. This is the single place the default lives.
96
+ * UI クロームロケールの解決。`undefined` (prop 未指定) は既定の `"en"`、
97
+ * {@link VIRTUAL_SCROLL_LOCALES} の要素はそのまま返却。既定値を持つ唯一の場所。
98
+ *
99
+ * @param locale - Requested locale, or `undefined` for the default / 要求ロケール (`undefined` で既定)
100
+ * @returns The resolved supported locale / 解決済みの対応ロケール
101
+ * @throws {RangeError} When `locale` is neither `undefined` nor a supported locale (`null`, `""`,
102
+ * `"EN"`, `"ja-JP"`, `"fr"`, numbers, ...) — no language negotiation /
103
+ * `undefined` でも対応ロケールでもない場合 (`null`、`""`、`"EN"`、`"ja-JP"`、`"fr"`、数値など)。言語ネゴシエーションなし
104
+ */
105
+ export declare const resolveVirtualScrollLocale: (locale: VirtualScrollLocale | undefined) => VirtualScrollLocale;
106
+ /**
107
+ * Resolves the effective labels: the catalog of the resolved locale overlaid by `overrides`.
108
+ * Returns the frozen catalog itself (same identity) when `overrides` is `undefined`, otherwise a
109
+ * new frozen object. Inputs are never mutated.
110
+ * 実効ラベルの解決。解決済みロケールのカタログへ `overrides` を重ねた結果。`overrides` が
111
+ * `undefined` なら凍結カタログそのもの (同一参照)、それ以外は新しい凍結オブジェクトを返却。入力は不変。
112
+ *
113
+ * @param locale - Requested locale, or `undefined` for the default / 要求ロケール (`undefined` で既定)
114
+ * @param overrides - Per-key overrides, or `undefined` for none / キー単位の上書き (`undefined` で上書きなし)
115
+ * @returns The resolved, frozen labels / 解決済みの凍結ラベル
116
+ * @throws {RangeError} When the locale is unsupported, `overrides` is `null` or not an object,
117
+ * `overrides` is not a plain object (its prototype is neither `Object.prototype` nor `null`, e.g.
118
+ * an array or a class instance), an own key is not a label key, or a present own value is not a
119
+ * string with non-whitespace content. Only own properties are read /
120
+ * ロケールが非対応、`overrides` が `null` または非オブジェクト、`overrides` が素のオブジェクトでない
121
+ * (プロトタイプが `Object.prototype` でも `null` でもない。配列やクラスインスタンスなど)、自身のキーが
122
+ * ラベルキー外、または与えられた自身の値が空白以外の文字を含む文字列でない場合。読むのは自身の
123
+ * プロパティのみ
124
+ */
125
+ export declare const resolveVirtualScrollLabels: (locale: VirtualScrollLocale | undefined, overrides: VirtualScrollLabelOverrides | undefined) => VirtualScrollLabels;
126
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,uBAAwB,CAAA;AAE3D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzE;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,mBAAmB,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;CAAE,CAAA;AAEhH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,8GAAgK,CAAA;AAMtM;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAmBnG,CAAA;AAiCF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,mBAAmB,GAAG,SAAS,KAAG,mBASpF,CAAA;AAWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,mBAAmB,GAAG,SAAS,EAAE,WAAW,2BAA2B,GAAG,SAAS,KAAG,mBAiCxI,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @module pointerCapture
3
+ * @description The single capability rule for the Pointer Capture API, shared by every pointer interaction in this package.
4
+ *
5
+ * @description 本パッケージのすべてのポインタ操作が共有する、Pointer Capture API の唯一の能力判定モジュール。
6
+ *
7
+ * `ScrollPane` (コンテンツのドラッグスクロール)・`ScrollBar` (サム / トラックのドラッグ)・
8
+ * `TapScrollCircle` (タップスクロールサークル) は、キャプチャの取得・解放・保持確認を
9
+ * 必ずここを通して行う。要素の `setPointerCapture` / `releasePointerCapture` /
10
+ * `hasPointerCapture` を直接呼んではならない。
11
+ *
12
+ * ❗ **3 つのメソッドが揃っている要素だけを「対応」とみなす。** jsdom (React のテストの既定環境) は
13
+ * このどれも実装しないため、直接呼ぶと利用側の `user.click` 1 回で `TypeError` になる。
14
+ * 一部だけを実装する環境で「取得はしたが解放も確認もできない」状態を作らないよう、判定は 1 本にしてある。
15
+ *
16
+ * 非対応の要素ではキャプチャ無しで操作を続ける (縮退)。コンテンツ領域とサムのドラッグは
17
+ * `window` / `document` のリスナーが追従を受け持つため動き続け、トラックとタップサークルは
18
+ * ポインタが要素上にある間だけ追従する。失われるのは、ウインドウ外や iframe 上で離したときの
19
+ * 終端イベントの受信と、`lostpointercapture` による強制解放の検知である。
20
+ */
21
+ /**
22
+ * Outcome of a pointer capture request.
23
+ * ポインタキャプチャ要求の結果。
24
+ *
25
+ * - `"captured"`: The element now holds the capture. / 要素がキャプチャを保持した。
26
+ * - `"unsupported"`: The element does not implement the Pointer Capture API; nothing was attempted. / 要素が API を実装しておらず、要求自体を行っていない。
27
+ * - `"inactive-pointer"`: The UA rejected the pointer as inactive (`NotFoundError`). / ポインタが非アクティブとして拒否された (`NotFoundError`)。
28
+ * - `"rejected"`: The UA rejected the request for any other reason. / それ以外の理由で拒否された。
29
+ */
30
+ export type PointerCaptureResult = "captured" | "unsupported" | "inactive-pointer" | "rejected";
31
+ /**
32
+ * Reports whether the element implements the whole Pointer Capture API.
33
+ * 要素が Pointer Capture API (取得・解放・保持確認の 3 メソッド) をすべて実装しているかの判定処理。
34
+ *
35
+ * @param element The element to inspect. 判定対象の要素。
36
+ * @returns True when set / release / has are all callable. 3 メソッドがすべて呼び出し可能な場合に true。
37
+ */
38
+ export declare const supportsPointerCapture: (element: Element) => boolean;
39
+ /**
40
+ * Reports whether the element holds (or has a pending) capture of the pointer.
41
+ * 要素が指定ポインタのキャプチャを保持 (または保留) しているかの判定処理。
42
+ *
43
+ * @param element The element to inspect. 判定対象の要素。
44
+ * @param pointerId The pointer to look up. 対象のポインタ ID。
45
+ * @returns True when the capture is held; always false when the API is unsupported. 保持している場合に true。API 非対応の要素では常に false。
46
+ */
47
+ export declare const isPointerCaptured: (element: Element, pointerId: number) => boolean;
48
+ /**
49
+ * Requests capture of the pointer for the element and classifies the outcome without throwing.
50
+ * 要素へ指定ポインタのキャプチャを要求し、例外を投げずに結果を分類する処理。
51
+ *
52
+ * @param element The element that should receive the capture. キャプチャを受け取る要素。
53
+ * @param pointerId The pointer to capture. キャプチャするポインタ ID。
54
+ * @returns The classified outcome of the request. 要求結果の分類。
55
+ */
56
+ export declare const capturePointer: (element: Element, pointerId: number) => PointerCaptureResult;
57
+ /**
58
+ * Releases the element's capture of the pointer when it holds one; does nothing otherwise.
59
+ * 要素が指定ポインタのキャプチャを保持していれば解放し、保持していなければ何もしない処理。
60
+ *
61
+ * 呼び出し側が状態を確定させてから呼ぶこと。`lostpointercapture` を同期発火するブラウザでは、
62
+ * この呼び出しの最中に喪失ハンドラーが走る。
63
+ *
64
+ * @param element The element that may hold the capture. キャプチャを保持している可能性のある要素。
65
+ * @param pointerId The pointer to release. 解放するポインタ ID。
66
+ * @returns Nothing. なし。
67
+ */
68
+ export declare const releaseCapturedPointer: (element: Element, pointerId: number) => void;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @module pointerCapture
3
+ * @description The single capability rule for the Pointer Capture API, shared by every pointer interaction in this package.
4
+ *
5
+ * @description 本パッケージのすべてのポインタ操作が共有する、Pointer Capture API の唯一の能力判定モジュール。
6
+ *
7
+ * `ScrollPane` (コンテンツのドラッグスクロール)・`ScrollBar` (サム / トラックのドラッグ)・
8
+ * `TapScrollCircle` (タップスクロールサークル) は、キャプチャの取得・解放・保持確認を
9
+ * 必ずここを通して行う。要素の `setPointerCapture` / `releasePointerCapture` /
10
+ * `hasPointerCapture` を直接呼んではならない。
11
+ *
12
+ * ❗ **3 つのメソッドが揃っている要素だけを「対応」とみなす。** jsdom (React のテストの既定環境) は
13
+ * このどれも実装しないため、直接呼ぶと利用側の `user.click` 1 回で `TypeError` になる。
14
+ * 一部だけを実装する環境で「取得はしたが解放も確認もできない」状態を作らないよう、判定は 1 本にしてある。
15
+ *
16
+ * 非対応の要素ではキャプチャ無しで操作を続ける (縮退)。コンテンツ領域とサムのドラッグは
17
+ * `window` / `document` のリスナーが追従を受け持つため動き続け、トラックとタップサークルは
18
+ * ポインタが要素上にある間だけ追従する。失われるのは、ウインドウ外や iframe 上で離したときの
19
+ * 終端イベントの受信と、`lostpointercapture` による強制解放の検知である。
20
+ */
21
+ /**
22
+ * Outcome of a pointer capture request.
23
+ * ポインタキャプチャ要求の結果。
24
+ *
25
+ * - `"captured"`: The element now holds the capture. / 要素がキャプチャを保持した。
26
+ * - `"unsupported"`: The element does not implement the Pointer Capture API; nothing was attempted. / 要素が API を実装しておらず、要求自体を行っていない。
27
+ * - `"inactive-pointer"`: The UA rejected the pointer as inactive (`NotFoundError`). / ポインタが非アクティブとして拒否された (`NotFoundError`)。
28
+ * - `"rejected"`: The UA rejected the request for any other reason. / それ以外の理由で拒否された。
29
+ */
30
+ export type PointerCaptureResult = "captured" | "unsupported" | "inactive-pointer" | "rejected";
31
+ /**
32
+ * Reports whether the element implements the whole Pointer Capture API.
33
+ * 要素が Pointer Capture API (取得・解放・保持確認の 3 メソッド) をすべて実装しているかの判定処理。
34
+ *
35
+ * @param element The element to inspect. 判定対象の要素。
36
+ * @returns True when set / release / has are all callable. 3 メソッドがすべて呼び出し可能な場合に true。
37
+ */
38
+ export declare const supportsPointerCapture: (element: Element) => boolean;
39
+ /**
40
+ * Reports whether the element holds (or has a pending) capture of the pointer.
41
+ * 要素が指定ポインタのキャプチャを保持 (または保留) しているかの判定処理。
42
+ *
43
+ * @param element The element to inspect. 判定対象の要素。
44
+ * @param pointerId The pointer to look up. 対象のポインタ ID。
45
+ * @returns True when the capture is held; always false when the API is unsupported. 保持している場合に true。API 非対応の要素では常に false。
46
+ */
47
+ export declare const isPointerCaptured: (element: Element, pointerId: number) => boolean;
48
+ /**
49
+ * Requests capture of the pointer for the element and classifies the outcome without throwing.
50
+ * 要素へ指定ポインタのキャプチャを要求し、例外を投げずに結果を分類する処理。
51
+ *
52
+ * @param element The element that should receive the capture. キャプチャを受け取る要素。
53
+ * @param pointerId The pointer to capture. キャプチャするポインタ ID。
54
+ * @returns The classified outcome of the request. 要求結果の分類。
55
+ */
56
+ export declare const capturePointer: (element: Element, pointerId: number) => PointerCaptureResult;
57
+ /**
58
+ * Releases the element's capture of the pointer when it holds one; does nothing otherwise.
59
+ * 要素が指定ポインタのキャプチャを保持していれば解放し、保持していなければ何もしない処理。
60
+ *
61
+ * 呼び出し側が状態を確定させてから呼ぶこと。`lostpointercapture` を同期発火するブラウザでは、
62
+ * この呼び出しの最中に喪失ハンドラーが走る。
63
+ *
64
+ * @param element The element that may hold the capture. キャプチャを保持している可能性のある要素。
65
+ * @param pointerId The pointer to release. 解放するポインタ ID。
66
+ * @returns Nothing. なし。
67
+ */
68
+ export declare const releaseCapturedPointer: (element: Element, pointerId: number) => void;
69
+ //# sourceMappingURL=pointerCapture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointerCapture.d.ts","sourceRoot":"","sources":["../src/pointerCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,aAAa,GAAG,kBAAkB,GAAG,UAAU,CAAA;AAE/F;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,OAAO,KAAG,OAAoK,CAAA;AAE9N;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,EAAE,WAAW,MAAM,KAAG,OAAkF,CAAA;AAE1J;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,OAAO,EAAE,WAAW,MAAM,KAAG,oBAYpE,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,OAAO,EAAE,WAAW,MAAM,KAAG,IAI5E,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/virtualscroll",
3
- "version": "3.6.1",
3
+ "version": "3.7.1",
4
4
  "description": "High-performance virtual scrolling component for React with variable item heights",
5
5
  "sideEffects": [
6
6
  "**/*.css"
package/src/ScrollBar.tsx CHANGED
@@ -6,7 +6,9 @@
6
6
  import type { CSSProperties, ReactNode } from "react"
7
7
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
8
8
  import { twMerge } from "tailwind-merge"
9
+ import { resolveVirtualScrollLabels, type VirtualScrollLabelOverrides, type VirtualScrollLocale } from "./labels.ts"
9
10
  import { Logger } from "./logger.ts"
11
+ import { capturePointer, releaseCapturedPointer } from "./pointerCapture.ts"
10
12
  import { TapScrollCircle, type TapScrollCircleDragState, type TapScrollCircleHandle, type TapScrollCircleRenderProps } from "./TapScrollCircle.tsx"
11
13
  import { getAxisScale, minmax } from "./utils.ts"
12
14
 
@@ -21,7 +23,6 @@ type OrientationConfig = {
21
23
  positionKey: "left" | "top"
22
24
  selectDelta: (deltaX: number, deltaY: number) => number
23
25
  getPointerCoordinate: (point: { clientX: number; clientY: number }) => number
24
- arrowLabels: [string, string]
25
26
  arrowIcons: [string, string]
26
27
  directionClass: string
27
28
  orientation: "vertical" | "horizontal"
@@ -193,6 +194,21 @@ export type ScrollBarProps = {
193
194
  visibleStartIndex?: number
194
195
  /** The index of the last visible item. / 最後の可視アイテムのインデックス。 */
195
196
  visibleEndIndex?: number
197
+ /**
198
+ * UI chrome locale of the built-in arrow aria-labels (default `"en"`). An unsupported value
199
+ * throws a RangeError at render; no language negotiation happens.
200
+ * 内蔵矢印 aria-label の UI クロームロケール (既定 `"en"`)。非対応値は描画時に RangeError、
201
+ * 言語ネゴシエーションなし。
202
+ */
203
+ locale?: VirtualScrollLocale
204
+ /**
205
+ * Per-key overrides laid over the catalog of `locale`. This bar reads `scrollUp` / `scrollDown`
206
+ * (vertical) or `scrollLeft` / `scrollRight` (horizontal); unknown keys and blank values throw a
207
+ * RangeError at render.
208
+ * `locale` のカタログへ重ねるキー単位の上書き。本バーが読むのは縦なら `scrollUp` / `scrollDown`、
209
+ * 横なら `scrollLeft` / `scrollRight`。未知キーと空白値は描画時に RangeError。
210
+ */
211
+ labels?: VirtualScrollLabelOverrides
196
212
  }
197
213
 
198
214
  /** The minimum size of the scrollbar thumb. / スクロールバーのつまみの最小サイズ。 */
@@ -255,7 +271,6 @@ const createOrientationConfig = (horizontal: boolean): OrientationConfig => {
255
271
  positionKey: "left",
256
272
  selectDelta: (deltaX: number, _deltaY: number) => deltaX,
257
273
  getPointerCoordinate: ({ clientX }) => clientX,
258
- arrowLabels: ["Scroll left", "Scroll right"],
259
274
  arrowIcons: ["◀", "▶"],
260
275
  directionClass: "aqvs-scrollbar-horizontal",
261
276
  orientation: "horizontal",
@@ -268,7 +283,6 @@ const createOrientationConfig = (horizontal: boolean): OrientationConfig => {
268
283
  positionKey: "top",
269
284
  selectDelta: (_deltaX: number, deltaY: number) => deltaY,
270
285
  getPointerCoordinate: ({ clientY }) => clientY,
271
- arrowLabels: ["Scroll up", "Scroll down"],
272
286
  arrowIcons: ["▲", "▼"],
273
287
  directionClass: "aqvs-scrollbar-vertical",
274
288
  orientation: "vertical",
@@ -608,6 +622,8 @@ export const ScrollBar = ({
608
622
  renderThumbOverlay,
609
623
  visibleStartIndex,
610
624
  visibleEndIndex,
625
+ locale,
626
+ labels,
611
627
  }: ScrollBarProps) => {
612
628
  const [isDragging, setIsDragging] = useState(false)
613
629
  const [isThumbHovered, setIsThumbHovered] = useState(false)
@@ -635,6 +651,8 @@ export const ScrollBar = ({
635
651
  const autoScrollDirectionRef = useRef<0 | 1 | -1>(0)
636
652
  const resolvedTapScrollOptions = useMemo<ResolvedTapScrollCircleOptions>(() => resolveTapScrollCircleOptions(tapScrollCircleOptions, itemCount), [itemCount, tapScrollCircleOptions])
637
653
  const orientationConfig = useMemo(() => createOrientationConfig(horizontal), [horizontal])
654
+ const resolvedLabels = useMemo(() => resolveVirtualScrollLabels(locale, labels), [locale, labels])
655
+ const arrowLabels = horizontal ? ([resolvedLabels.scrollLeft, resolvedLabels.scrollRight] as const) : ([resolvedLabels.scrollUp, resolvedLabels.scrollDown] as const)
638
656
  const {
639
657
  enabled: tapCircleEnabled,
640
658
  size: tapCircleSize,
@@ -661,7 +679,7 @@ export const ScrollBar = ({
661
679
  onScroll,
662
680
  scrollPosition,
663
681
  })
664
- const { mainSizeKey, crossSizeKey, positionKey, selectDelta, getPointerCoordinate, arrowLabels, arrowIcons, directionClass, orientation } = orientationConfig
682
+ const { mainSizeKey, crossSizeKey, positionKey, selectDelta, getPointerCoordinate, arrowIcons, directionClass, orientation } = orientationConfig
665
683
  const effectiveTapMaxDistance = Math.max(tapCircleMaxDistance, 1)
666
684
  // 表示領域に対するコンテンツの比率
667
685
  const scrollRatio = viewportSize / contentSize
@@ -1119,10 +1137,10 @@ export const ScrollBar = ({
1119
1137
 
1120
1138
  /**
1121
1139
  * Pointer up handler for thumb dragging.
1122
- * Cleans up drag state and visual feedback.
1140
+ * Cleans up drag state and visual feedback, releasing the capture only when the press acquired one.
1123
1141
  *
1124
1142
  * つまみドラッグ用のポインタ上げハンドラー。
1125
- * ドラッグ状態と視覚的フィードバックをクリーンアップします。
1143
+ * ドラッグ状態と視覚的フィードバックをクリーンアップし、押下時にキャプチャを取得できていた場合だけ解放します。
1126
1144
  */
1127
1145
  const handleThumbPointerUp = useCallback(
1128
1146
  (event: PointerEvent) => {
@@ -1135,9 +1153,8 @@ export const ScrollBar = ({
1135
1153
  document.removeEventListener("pointerup", handleThumbPointerUp)
1136
1154
  document.removeEventListener("pointercancel", handleThumbPointerUp)
1137
1155
 
1138
- const captureTarget = state.captureTarget
1139
- if (captureTarget?.hasPointerCapture?.(event.pointerId)) {
1140
- captureTarget.releasePointerCapture(event.pointerId)
1156
+ if (state.captureTarget !== null) {
1157
+ releaseCapturedPointer(state.captureTarget, event.pointerId)
1141
1158
  }
1142
1159
 
1143
1160
  thumbDragStateRef.current = { pointerId: null, startThumbPosition: 0, startClientX: 0, startClientY: 0, scale: 1, captureTarget: null }
@@ -1210,8 +1227,10 @@ export const ScrollBar = ({
1210
1227
  // スクロールバーのつまみをポインタイベントで処理
1211
1228
  /**
1212
1229
  * Handles pointer down interaction on the thumb.
1230
+ * Captures the pointer when the element supports it; otherwise the drag continues on the document listeners alone.
1213
1231
  *
1214
1232
  * つまみ押下時のインタラクションを処理。
1233
+ * 要素がキャプチャに対応していれば取得し、取得できなければ document のリスナーだけでドラッグを続ける。
1215
1234
  */
1216
1235
  const handlePointerDownOnThumb = (event: React.PointerEvent<HTMLDivElement>) => {
1217
1236
  if (!scrollBarVisible) {
@@ -1230,18 +1249,10 @@ export const ScrollBar = ({
1230
1249
 
1231
1250
  // ポインターキャプチャを取得し、iframe/ウィンドウ外での pointerup 取りこぼしによる
1232
1251
  // ドラッグ固着を防ぐ。キャプチャ後もイベントは document までバブリングするため既存の
1233
- // document リスナはそのまま機能する。取得不能なポインターでは例外を握り潰す。
1252
+ // document リスナはそのまま機能する。取得できなかったときは解放対象を持たない。
1234
1253
  const element = event.currentTarget
1235
1254
  const scale = getMainAxisScale(element)
1236
- let captureTarget: HTMLElement | null = null
1237
- if (element.setPointerCapture) {
1238
- try {
1239
- element.setPointerCapture(event.pointerId)
1240
- captureTarget = element
1241
- } catch {
1242
- captureTarget = null
1243
- }
1244
- }
1255
+ const captureTarget = capturePointer(element, event.pointerId) === "captured" ? element : null
1245
1256
 
1246
1257
  thumbDragStateRef.current = {
1247
1258
  pointerId: event.pointerId,
@@ -1265,8 +1276,10 @@ export const ScrollBar = ({
1265
1276
 
1266
1277
  /**
1267
1278
  * Handles pointer down interaction on the track.
1279
+ * Jumps to the pressed position and captures the pointer when the element supports it.
1268
1280
  *
1269
1281
  * トラック押下時のインタラクションを処理。
1282
+ * 押下位置へ移動し、要素がキャプチャに対応していれば取得する。
1270
1283
  */
1271
1284
  const handlePointerDownOnTrack = (event: React.PointerEvent<HTMLDivElement>) => {
1272
1285
  if (!scrollBarVisible) {
@@ -1294,15 +1307,9 @@ export const ScrollBar = ({
1294
1307
  const initialPosition = translateToScrollPosition(startThumbPosition)
1295
1308
  resolveScrollRequest(initialPosition)
1296
1309
 
1297
- // サム側と同様、取得不能なポインター (非アクティブ pointerId 等) では例外を握り潰し、
1298
- // キャプチャなしのフォールバックでドラッグ状態の設定と preventDefault を継続する。
1299
- if (element.setPointerCapture) {
1300
- try {
1301
- element.setPointerCapture(event.pointerId)
1302
- } catch {
1303
- // キャプチャ取得失敗時はキャプチャなしで続行 (要素上の pointermove では追従する)。
1304
- }
1305
- }
1310
+ // 取得できなくても (非アクティブ pointerId・API 非対応) ドラッグ状態の設定と preventDefault は続ける。
1311
+ // キャプチャ無しでも要素上の pointermove では追従する。
1312
+ capturePointer(element, event.pointerId)
1306
1313
 
1307
1314
  trackDragStateRef.current = {
1308
1315
  pointerId: event.pointerId,
@@ -1357,19 +1364,17 @@ export const ScrollBar = ({
1357
1364
 
1358
1365
  /**
1359
1366
  * Handles pointer up interaction on the track.
1367
+ * Releases the capture when held and ends the track drag.
1360
1368
  *
1361
1369
  * トラックドラッグ終了時の処理。
1370
+ * キャプチャを保持していれば解放し、トラックドラッグを終える。
1362
1371
  */
1363
1372
  const handlePointerUpOnTrack = (event: React.PointerEvent<HTMLDivElement>) => {
1364
1373
  if (trackDragStateRef.current.pointerId !== event.pointerId) {
1365
1374
  return
1366
1375
  }
1367
1376
 
1368
- // hasPointerCapture は API 非実装環境 (jsdom 等) を考慮してサム側と同様に存在ガード付きで呼ぶ。
1369
- const element = event.currentTarget
1370
- if (element.hasPointerCapture?.(event.pointerId)) {
1371
- element.releasePointerCapture(event.pointerId)
1372
- }
1377
+ releaseCapturedPointer(event.currentTarget, event.pointerId)
1373
1378
 
1374
1379
  resetTrackDragState()
1375
1380
 
@@ -1379,19 +1384,17 @@ export const ScrollBar = ({
1379
1384
 
1380
1385
  /**
1381
1386
  * Handles pointer cancel interaction on the track.
1387
+ * Releases the capture when held and discards the track drag.
1382
1388
  *
1383
1389
  * トラックドラッグキャンセル時の処理。
1390
+ * キャプチャを保持していれば解放し、トラックドラッグを破棄する。
1384
1391
  */
1385
1392
  const handlePointerCancelOnTrack = (event: React.PointerEvent<HTMLDivElement>) => {
1386
1393
  if (trackDragStateRef.current.pointerId !== event.pointerId) {
1387
1394
  return
1388
1395
  }
1389
1396
 
1390
- // hasPointerCapture は API 非実装環境 (jsdom 等) を考慮してサム側と同様に存在ガード付きで呼ぶ。
1391
- const element = event.currentTarget
1392
- if (element.hasPointerCapture?.(event.pointerId)) {
1393
- element.releasePointerCapture(event.pointerId)
1394
- }
1397
+ releaseCapturedPointer(event.currentTarget, event.pointerId)
1395
1398
 
1396
1399
  resetTrackDragState()
1397
1400
  }