@aiquants/virtualscroll 1.18.5 → 1.19.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.
Files changed (40) hide show
  1. package/README.md +20 -13
  2. package/dist/ScrollPane.d.cts +2 -0
  3. package/dist/ScrollPane.d.ts +2 -0
  4. package/dist/ScrollPane.d.ts.map +1 -1
  5. package/dist/VirtualScroll.d.cts +2 -0
  6. package/dist/VirtualScroll.d.ts +2 -0
  7. package/dist/VirtualScroll.d.ts.map +1 -1
  8. package/dist/index.cjs +1 -1
  9. package/dist/index.d.cts +6 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1115 -1112
  13. package/dist/styles/virtualscroll.css +1 -1
  14. package/dist/styles/virtualscroll.standalone.css +3 -0
  15. package/package.json +6 -4
  16. package/src/ScrollBar.spec.tsx +620 -0
  17. package/src/ScrollBar.tsx +1397 -0
  18. package/src/ScrollPane.spec.tsx +482 -0
  19. package/src/ScrollPane.tsx +913 -0
  20. package/src/TapScrollCircle.spec.tsx +275 -0
  21. package/src/TapScrollCircle.tsx +363 -0
  22. package/src/VirtualScroll.spec.ts +623 -0
  23. package/src/VirtualScroll.tsx +1891 -0
  24. package/src/cli.server.spec.ts +137 -0
  25. package/src/cli.server.ts +110 -0
  26. package/src/index.ts +24 -0
  27. package/src/logger.spec.ts +128 -0
  28. package/src/logger.ts +229 -0
  29. package/src/styles/components.entry.css +7 -0
  30. package/src/styles/standalone.entry.css +11 -0
  31. package/src/styles/virtualscroll.css +298 -0
  32. package/src/tapScrollCircleSampleVisual.tsx +74 -0
  33. package/src/useFenwickMapTree.huge.spec.ts +388 -0
  34. package/src/useFenwickMapTree.spec.ts +1518 -0
  35. package/src/useFenwickMapTree.ts +1368 -0
  36. package/src/useHeightCache.ts +32 -0
  37. package/src/useLruCache.spec.ts +382 -0
  38. package/src/useLruCache.ts +301 -0
  39. package/src/utils.spec.ts +39 -0
  40. package/src/utils.ts +16 -0
@@ -0,0 +1,298 @@
1
+ @layer utilities {
2
+ .aqvs-scroll-pane {
3
+ position: relative;
4
+ display: flex;
5
+ }
6
+
7
+ .aqvs-scroll-pane-content {
8
+ position: relative;
9
+ height: 100%;
10
+ flex: 1 1 0%;
11
+ overflow: hidden;
12
+ }
13
+
14
+ .aqvs-tap-scroll-circle {
15
+ position: relative;
16
+ display: flex;
17
+ touch-action: none;
18
+ user-select: none;
19
+ align-items: center;
20
+ justify-content: center;
21
+ transition-property: transform;
22
+ transition-duration: 100ms;
23
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
24
+ }
25
+
26
+ .aqvs-tap-scroll-circle-visual-outer {
27
+ position: absolute;
28
+ inset: 0;
29
+ border-radius: 9999px;
30
+ }
31
+
32
+ .aqvs-tap-scroll-circle-gradient {
33
+ background: linear-gradient(to bottom right, rgba(29, 78, 216, 0.6), rgba(96, 165, 250, 0.55), rgba(191, 219, 254, 0.4));
34
+ position: absolute;
35
+ inset: 0;
36
+ border-radius: 9999px;
37
+ border-width: 1px;
38
+ border-color: rgba(255, 255, 255, 0.4);
39
+ box-shadow:
40
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
41
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
42
+ }
43
+
44
+ .aqvs-tap-scroll-circle-inner {
45
+ inset: 18%;
46
+ position: absolute;
47
+ border-radius: 9999px;
48
+ }
49
+
50
+ .aqvs-sample-visual-rod {
51
+ position: absolute;
52
+ top: 50%;
53
+ left: 50%;
54
+ border-radius: 9999px;
55
+ border-width: 1px;
56
+ border-color: rgba(255, 255, 255, 0.5);
57
+ background-color: rgba(255, 255, 255, 0.85);
58
+ }
59
+
60
+ .aqvs-sample-visual-pupil {
61
+ position: absolute;
62
+ top: 50%;
63
+ left: 50%;
64
+ border-radius: 9999px;
65
+ background-color: rgba(255, 255, 255, 0.8);
66
+ }
67
+
68
+ .aqvs-sample-visual-highlight {
69
+ position: absolute;
70
+ top: 50%;
71
+ left: 50%;
72
+ border-radius: 9999px;
73
+ background-color: rgba(255, 255, 255, 0.5);
74
+ }
75
+
76
+ .aqvs-scrollbar {
77
+ position: relative;
78
+ z-index: 50;
79
+ cursor: default;
80
+ user-select: none;
81
+ background-color: white;
82
+ touch-action: none;
83
+ }
84
+
85
+ .aqvs-scrollbar-horizontal {
86
+ display: flex;
87
+ flex-direction: row;
88
+ align-items: stretch;
89
+ }
90
+
91
+ .aqvs-scrollbar-vertical {
92
+ display: flex;
93
+ flex-direction: column;
94
+ align-items: stretch;
95
+ }
96
+
97
+ .aqvs-scrollbar-tap-circle-wrapper {
98
+ pointer-events: auto;
99
+ position: absolute;
100
+ transition-property: opacity;
101
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
102
+ transition-duration: 150ms;
103
+ }
104
+
105
+ .aqvs-scrollbar-arrow-button {
106
+ color: #313131;
107
+ background-color: #e0e0e0;
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ font-size: 0.75rem;
112
+ line-height: 1rem;
113
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
114
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
115
+ transition-duration: 150ms;
116
+ }
117
+
118
+ .aqvs-scrollbar-arrow-button:focus {
119
+ outline: 2px solid transparent;
120
+ outline-offset: 2px;
121
+ }
122
+
123
+ .aqvs-scrollbar-arrow-button:focus-visible {
124
+ outline: 2px solid rgba(96, 165, 250, 1);
125
+ outline-offset: 1px;
126
+ }
127
+
128
+ .aqvs-scrollbar-arrow-button:disabled {
129
+ cursor: not-allowed;
130
+ opacity: 0.5;
131
+ }
132
+
133
+ .aqvs-scrollbar-arrow-button:enabled:hover {
134
+ background-color: #d4d4d4;
135
+ }
136
+
137
+ .aqvs-scrollbar-track {
138
+ background-color: #f5f5f5;
139
+ position: relative;
140
+ flex: 1 1 0%;
141
+ }
142
+
143
+ .aqvs-scrollbar-overlay {
144
+ pointer-events: none;
145
+ position: absolute;
146
+ inset: 0;
147
+ }
148
+
149
+ .aqvs-scrollbar-thumb-wrapper {
150
+ position: absolute;
151
+ touch-action: none;
152
+ }
153
+
154
+ .aqvs-scrollbar-thumb {
155
+ background-color: #7f7f7f;
156
+ transition: transform 80ms ease-out;
157
+ transform-origin: center;
158
+ position: absolute;
159
+ }
160
+
161
+ .aqvs-scrollbar-thumb[data-thumb-state="disabled"] {
162
+ transform: none;
163
+ transition: none;
164
+ }
165
+
166
+ .aqvs-scrollbar-thumb[data-thumb-state="hover"] {
167
+ background-color: #5f5f5f;
168
+ }
169
+
170
+ .aqvs-scrollbar-thumb[data-thumb-state="dragging"] {
171
+ background-color: #4f4f4f;
172
+ transition: transform 60ms ease-out;
173
+ }
174
+
175
+ .aqvs-scrollbar-thumb-horizontal {
176
+ top: 1.5px;
177
+ bottom: 1.5px;
178
+ left: 0;
179
+ right: 0;
180
+ }
181
+
182
+ .aqvs-scrollbar-thumb-horizontal[data-thumb-state="hover"] {
183
+ transform: scaleY(1.06);
184
+ top: -0.5px;
185
+ bottom: -0.5px;
186
+ }
187
+
188
+ .aqvs-scrollbar-thumb-horizontal[data-thumb-state="dragging"] {
189
+ transform: scaleY(1.12);
190
+ top: -0.5px;
191
+ bottom: -0.5px;
192
+ }
193
+
194
+ .aqvs-scrollbar-thumb-vertical {
195
+ top: 0;
196
+ bottom: 0;
197
+ left: 1.5px;
198
+ right: 1.5px;
199
+ }
200
+
201
+ .aqvs-scrollbar-thumb-vertical[data-thumb-state="hover"] {
202
+ transform: scaleX(1.06);
203
+ left: -0.5px;
204
+ right: -0.5px;
205
+ }
206
+
207
+ .aqvs-scrollbar-thumb-vertical[data-thumb-state="dragging"] {
208
+ transform: scaleX(1.12);
209
+ left: -0.5px;
210
+ right: -0.5px;
211
+ }
212
+
213
+ .aqvs-scroll-to-edge-button {
214
+ pointer-events: auto;
215
+ transform: none;
216
+ border-radius: 9999px;
217
+ background-color: rgba(31, 41, 55, 0.8);
218
+ padding: 0.25rem 3rem;
219
+ font-weight: 500;
220
+ font-size: 10px;
221
+ color: white;
222
+ text-transform: uppercase;
223
+ letter-spacing: 0.05em;
224
+ box-shadow:
225
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
226
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
227
+ backdrop-filter: blur(4px);
228
+ transition-property: transform, background-color;
229
+ transition-duration: 150ms;
230
+ }
231
+
232
+ .aqvs-scroll-to-edge-button:hover {
233
+ background-color: rgba(55, 65, 81, 1);
234
+ }
235
+
236
+ .aqvs-scroll-to-edge-button:active {
237
+ transform: scale(0.95);
238
+ }
239
+
240
+ .aqvs-scroll-to-edge-overlay {
241
+ pointer-events: none;
242
+ position: absolute;
243
+ inset: 0;
244
+ transition-property: opacity;
245
+ transition-duration: 500ms;
246
+ z-index: 10;
247
+ }
248
+
249
+ .aqvs-scroll-to-edge-overlay[data-visible="true"] {
250
+ opacity: 1;
251
+ }
252
+
253
+ .aqvs-scroll-to-edge-overlay[data-visible="false"] {
254
+ opacity: 0;
255
+ }
256
+
257
+ .aqvs-scroll-to-edge-button-container {
258
+ position: absolute;
259
+ left: 0;
260
+ right: 0;
261
+ display: flex;
262
+ justify-content: center;
263
+ }
264
+
265
+ .aqvs-scroll-to-edge-button-container-top {
266
+ top: 0.5rem;
267
+ }
268
+
269
+ .aqvs-scroll-to-edge-button-container-bottom {
270
+ bottom: 0.5rem;
271
+ }
272
+
273
+ .aqvs-no-items-container {
274
+ position: absolute;
275
+ width: 100%;
276
+ top: 0;
277
+ }
278
+
279
+ .aqvs-no-items-text {
280
+ text-align: center;
281
+ color: #6b7280;
282
+ }
283
+
284
+ .aqvs-item-container {
285
+ position: absolute;
286
+ width: 100%;
287
+ }
288
+
289
+ .aqvs-bottom-inset {
290
+ position: absolute;
291
+ width: 100%;
292
+ }
293
+
294
+ .aqvs-items-wrapper {
295
+ position: absolute;
296
+ width: 100%;
297
+ }
298
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Provides the sample tap scroll circle visual used for demos.
3
+ * デモ用に使用されるサンプルのタップスクロールビジュアルを提供するモジュール。
4
+ */
5
+
6
+ import type { TapScrollCircleProps, TapScrollCircleRenderProps } from "./TapScrollCircle.tsx"
7
+
8
+ const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)
9
+
10
+ export const tapScrollCircleSampleVisual: NonNullable<TapScrollCircleProps["renderVisual"]> = ({ dragState, normalizedDistance, sizeScale, size }: TapScrollCircleRenderProps) => {
11
+ const radius = Math.max(size / 2, 1)
12
+ const stretchY = 1 + normalizedDistance * 0.65
13
+ const stretchX = Math.max(0.65, 1 - normalizedDistance * 0.25)
14
+ const tail = dragState.direction * normalizedDistance * 26 * sizeScale
15
+ const pupilScale = 0.8 + normalizedDistance * 0.18
16
+ const tailBase = 3 * sizeScale
17
+ const baseHeight = 6 * sizeScale
18
+ const coreSize = 22 * sizeScale
19
+ const rodHeight = Math.abs(tail) + baseHeight
20
+ const rodTranslate = tail > 0 ? tailBase : -Math.abs(tail) - tailBase
21
+ const rodWidth = Math.max(2.5, 3 * sizeScale)
22
+ const limitedX = clamp(dragState.offsetX, -radius, radius)
23
+ const limitedY = clamp(dragState.offsetY, -radius, radius)
24
+ const pupilRange = radius * 0.35
25
+ const pupilX = (limitedX / radius) * pupilRange
26
+ const pupilY = (limitedY / radius) * pupilRange
27
+ const highlightX = pupilX * 0.45
28
+ const highlightY = pupilY * 0.45
29
+ const highlightSize = Math.max(coreSize * 0.38, 6)
30
+ const highlightOpacity = 0.65 + normalizedDistance * 0.2
31
+ const active = dragState.active
32
+
33
+ return (
34
+ <>
35
+ <div
36
+ className="aqvs-tap-scroll-circle-gradient"
37
+ style={{
38
+ transform: `scale(${stretchX}, ${stretchY})`,
39
+ transition: active ? "40ms transform ease-out" : "200ms ease transform",
40
+ }}
41
+ />
42
+ <div
43
+ className="aqvs-sample-visual-rod"
44
+ style={{
45
+ width: coreSize,
46
+ height: coreSize,
47
+ transform: `translate(calc(-50% + ${pupilX}px), calc(-50% + ${pupilY}px)) scale(${stretchX}, ${pupilScale * stretchY})`,
48
+ transition: active ? "70ms transform ease-out" : "200ms ease transform",
49
+ }}
50
+ />
51
+ <div
52
+ className="aqvs-sample-visual-pupil"
53
+ style={{
54
+ width: highlightSize,
55
+ height: highlightSize,
56
+ transform: `translate(calc(-50% + ${highlightX}px), calc(-50% + ${highlightY}px)) scale(${stretchX}, ${stretchY})`,
57
+ opacity: highlightOpacity,
58
+ boxShadow: "0 0 8px rgba(255,255,255,0.45)",
59
+ transition: active ? "120ms opacity 150ms, 120ms transform ease-out ease-out" : "220ms ease transform, 240ms opacity ease",
60
+ }}
61
+ />
62
+ <div
63
+ className="aqvs-sample-visual-highlight"
64
+ style={{
65
+ width: rodWidth,
66
+ height: rodHeight,
67
+ transform: `translate(-50%, ${rodTranslate}px)`,
68
+ opacity: normalizedDistance,
69
+ transition: active ? "40ms height, 60ms opacity ease-out ease-out" : "200ms ease height, 120ms ease opacity",
70
+ }}
71
+ />
72
+ </>
73
+ )
74
+ }