@rcarls/rc-virtual-scroller 0.0.0-next-20260925180130
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/CHANGELOG.md +45 -0
- package/README.md +132 -0
- package/dist/custom-elements.json +588 -0
- package/dist/rc-virtual-scroller-DAyMmvlM.js +301 -0
- package/dist/rc-virtual-scroller-DAyMmvlM.js.map +1 -0
- package/dist/rc-virtual-scroller-define.js +6 -0
- package/dist/rc-virtual-scroller-define.js.map +1 -0
- package/dist/rc-virtual-scroller.js +5 -0
- package/dist/rc-virtual-scroller.js.map +1 -0
- package/dist/types/packages/rc-virtual-scroller/src/define.d.ts +1 -0
- package/dist/types/packages/rc-virtual-scroller/src/index.d.ts +1 -0
- package/dist/types/packages/rc-virtual-scroller/src/rc-virtual-scroller.d.ts +198 -0
- package/dist/types/packages/rc-virtual-scroller/src/rc-virtual-scroller.styles.d.ts +2 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @rcarls/rc-virtual-scroller
|
|
2
|
+
|
|
3
|
+
## 0.0.0-next-20260925180130
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- aed2034: Add `rc-virtual-scroller`, a headless virtualization wrapper.
|
|
8
|
+
|
|
9
|
+
Mounting a large collection as custom elements costs real time regardless of
|
|
10
|
+
`content-visibility: auto`: upgrade happens at parse and insertion, before
|
|
11
|
+
style resolves, so containment cannot prevent element construction. This
|
|
12
|
+
package stops the count of mounted elements from scaling with collection
|
|
13
|
+
size, without taking over rendering.
|
|
14
|
+
|
|
15
|
+
The element measures geometry against a slotted container and dispatches
|
|
16
|
+
`rc-virtual-scroller-range` with the visible `[start, end)` index range; the
|
|
17
|
+
consumer renders that slice into its own container with whatever it already
|
|
18
|
+
uses, and two spacer parts reserve the off-range scroll space. Items per line
|
|
19
|
+
and line pitch are measured from the container's own grid tracks rather than
|
|
20
|
+
configured, so `auto-fill` and container queries stay authoritative. The
|
|
21
|
+
focused item is never dropped from the reported range, so scrolling never
|
|
22
|
+
silently resets keyboard focus to `<body>`.
|
|
23
|
+
|
|
24
|
+
`axis="block|inline"` is logical: `block` windows stacked lines, `inline`
|
|
25
|
+
windows a row of items such as a horizontal shelf. Direction and writing mode
|
|
26
|
+
are read from computed style, so RTL pages and vertical text work without
|
|
27
|
+
configuration.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 0c9d563: Re-resolve the writing direction when a `dir` attribute changes, and at the
|
|
32
|
+
start of every `scrollToIndex` call, so an inline-axis scroller keeps the
|
|
33
|
+
right range and scrolls to the right item after a page switches direction.
|
|
34
|
+
- Updated dependencies [50d5610]
|
|
35
|
+
- Updated dependencies [9ee769c]
|
|
36
|
+
- Updated dependencies [4341311]
|
|
37
|
+
- Updated dependencies [51f6403]
|
|
38
|
+
- Updated dependencies [9caca6b]
|
|
39
|
+
- Updated dependencies [b9175e9]
|
|
40
|
+
- Updated dependencies [f7f0270]
|
|
41
|
+
- Updated dependencies [32ebead]
|
|
42
|
+
- Updated dependencies [11680b6]
|
|
43
|
+
- Updated dependencies [223d36c]
|
|
44
|
+
- Updated dependencies [7b91a44]
|
|
45
|
+
- @rcarls/rc-common@0.0.0-next-20260925180130
|
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @rcarls/rc-virtual-scroller
|
|
2
|
+
|
|
3
|
+
Headless virtualization wrapper that reports the visible index range for a
|
|
4
|
+
consumer-owned list or grid and reserves the off-range scroll space.
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<rc-scroller>
|
|
8
|
+
<rc-virtual-scroller count="4000" item-size="288">
|
|
9
|
+
<ul class="cards">
|
|
10
|
+
<!-- only the items in the current range -->
|
|
11
|
+
</ul>
|
|
12
|
+
</rc-virtual-scroller>
|
|
13
|
+
</rc-scroller>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
const scroller = document.querySelector('rc-virtual-scroller');
|
|
18
|
+
|
|
19
|
+
const render = ({ start, end }) => renderItems(recipes.slice(start, end), start);
|
|
20
|
+
|
|
21
|
+
// The element may have measured before this listener existed.
|
|
22
|
+
if (scroller.range) render(scroller.range);
|
|
23
|
+
|
|
24
|
+
scroller.addEventListener('rc-virtual-scroller-range', (event) => render(event.detail));
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The element measures on its own schedule, which can be before your listener is
|
|
28
|
+
attached, and it never re-sends an unchanged range. Render once from the
|
|
29
|
+
read-only `range` property when you subscribe, then follow the event.
|
|
30
|
+
|
|
31
|
+
The element never creates, recycles, or positions item DOM. It measures
|
|
32
|
+
geometry, dispatches `rc-virtual-scroller-range`, and sizes two spacer parts
|
|
33
|
+
around the default slot. You slot one container element and render the reported
|
|
34
|
+
slice into it with whatever you already use.
|
|
35
|
+
|
|
36
|
+
That split is the whole point. The markup, the CSS layout, and the
|
|
37
|
+
accessibility semantics stay with the code that owns them, so a native
|
|
38
|
+
`grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr))` keeps working
|
|
39
|
+
untouched, `<ul>` still contains `<li>`, and a framework's keyed list still
|
|
40
|
+
reuses the nodes that stayed in range.
|
|
41
|
+
|
|
42
|
+
## Why not `content-visibility: auto`
|
|
43
|
+
|
|
44
|
+
CSS containment skips layout and paint for offscreen content, but a custom
|
|
45
|
+
element upgrades when it is parsed or inserted, before style is resolved.
|
|
46
|
+
Containment cannot prevent element construction, so a collection of a few
|
|
47
|
+
thousand custom elements still pays for all of them up front. Virtualization is
|
|
48
|
+
the only thing that avoids that cost.
|
|
49
|
+
|
|
50
|
+
## Axis, direction, and writing mode
|
|
51
|
+
|
|
52
|
+
`axis` is logical. `block`, the default, windows lines that stack the way
|
|
53
|
+
paragraphs do: top to bottom in horizontal text, right to left in
|
|
54
|
+
`vertical-rl`. `inline` windows items running the way text runs, such as a
|
|
55
|
+
horizontal shelf. For the inline axis, lay the container's items along it with
|
|
56
|
+
`display: flex` or a grid with `grid-auto-flow: column`.
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<rc-virtual-scroller axis="inline" count="500" item-size="160">
|
|
60
|
+
<ul class="shelf">
|
|
61
|
+
<!-- display: flex -->
|
|
62
|
+
</ul>
|
|
63
|
+
</rc-virtual-scroller>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Direction and writing mode come from the element's computed style, so RTL
|
|
67
|
+
pages and vertical text need no configuration. The visible range is measured
|
|
68
|
+
from where the scroll container's visible box sits relative to the element, in
|
|
69
|
+
the element's own flow, so it never depends on the sign conventions of
|
|
70
|
+
`scrollLeft` in RTL.
|
|
71
|
+
|
|
72
|
+
## Geometry
|
|
73
|
+
|
|
74
|
+
`count` is the true total. `item-size` is the estimated line pitch in pixels;
|
|
75
|
+
it is used for the first frame and whenever nothing can be measured yet, so a
|
|
76
|
+
reasonable value matters for the first paint and for restoring a saved scroll
|
|
77
|
+
position.
|
|
78
|
+
|
|
79
|
+
Items per line and line pitch are measured from the slotted container rather
|
|
80
|
+
than configured. On the block axis a line holds one item per grid column
|
|
81
|
+
(`grid-template-columns`); on the inline axis, one item per grid row
|
|
82
|
+
(`grid-template-rows`). Grid columns and rows are logical, so this holds in
|
|
83
|
+
vertical writing modes too. The pitch is the offset between two items one line
|
|
84
|
+
apart, which keeps `auto-fill`, container queries, and the gap authoritative in
|
|
85
|
+
CSS instead of duplicated in JavaScript. `rc-virtual-scroller-range` reports
|
|
86
|
+
`itemsPerLine`, `lineSize`, and a `measured` flag that is `false` while the
|
|
87
|
+
geometry is still the `item-size` estimate.
|
|
88
|
+
|
|
89
|
+
`overscan` (default `2`) is how many extra lines render past each edge.
|
|
90
|
+
`disabled` reports the whole collection as the range and stops measuring, which
|
|
91
|
+
makes an A/B against the non-virtualized cost a one-attribute change.
|
|
92
|
+
|
|
93
|
+
The element measures against the nearest scrolling ancestor. Set the
|
|
94
|
+
`scrollTarget` property when that ancestor only becomes scrollable after its own
|
|
95
|
+
upgrade, or when the real scrollport is further up the tree.
|
|
96
|
+
|
|
97
|
+
`scrollToIndex(index, { align, behavior })` scrolls an arbitrary index into
|
|
98
|
+
view along `axis`, including one that is not currently rendered. `align` is
|
|
99
|
+
`start` (the default), `center`, `end`, or `nearest`. It is accurate to the
|
|
100
|
+
current line pitch, so it is only as accurate as `item-size` until at least one
|
|
101
|
+
line has rendered.
|
|
102
|
+
|
|
103
|
+
## Accessibility
|
|
104
|
+
|
|
105
|
+
A virtualized set must still tell assistive technology how big it really is,
|
|
106
|
+
because the DOM no longer says so. The element does not write these for you:
|
|
107
|
+
the roles belong to your markup, and guessing at them would fight a container
|
|
108
|
+
that manages its own rows.
|
|
109
|
+
|
|
110
|
+
- For a list, put `aria-setsize` (the true `count`) and `aria-posinset` (the
|
|
111
|
+
item's real index, not its position in the rendered slice) on each item.
|
|
112
|
+
- For a grid, use `aria-rowcount` / `aria-rowindex`, and
|
|
113
|
+
`aria-colcount` / `aria-colindex` where columns are also virtualized.
|
|
114
|
+
- Set `aria-busy="true"` on the container while a batch is being swapped in, as
|
|
115
|
+
the [WAI-ARIA APG feed pattern](https://www.w3.org/WAI/ARIA/apg/patterns/feed/)
|
|
116
|
+
describes.
|
|
117
|
+
|
|
118
|
+
The one thing the element does handle is focus. Unmounting the focused element
|
|
119
|
+
moves focus to `<body>` with no error and no visible cause, which is how a
|
|
120
|
+
keyboard user silently loses their place. The reported range is always widened
|
|
121
|
+
to include the focused item, contiguously, so your render stays a plain slice;
|
|
122
|
+
it collapses again as soon as focus moves. Scrolling a long way while holding
|
|
123
|
+
focus therefore renders a larger range on purpose.
|
|
124
|
+
|
|
125
|
+
The element sets `overflow-anchor: none` on itself. Browser scroll anchoring
|
|
126
|
+
exists to hold the reading position when content above the viewport changes
|
|
127
|
+
size, which is what this element does every frame, so leaving it on makes the
|
|
128
|
+
two fight and the scroll position drift.
|
|
129
|
+
|
|
130
|
+
Import `@rcarls/rc-virtual-scroller` to use the class without registering it, or
|
|
131
|
+
import `@rcarls/rc-virtual-scroller/define` to register
|
|
132
|
+
`<rc-virtual-scroller>`.
|