@rcarls/rc-virtual-scroller 0.0.0 → 0.7.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/CHANGELOG.md ADDED
@@ -0,0 +1,96 @@
1
+ # @rcarls/rc-virtual-scroller
2
+
3
+ ## 0.7.0
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
+ - 11ef1ad: Harden virtual scrolling for document and element scroll containers, viewport resizing,
30
+ shadow-root focus, hidden panes, and uniform spanning grids. Separate layout
31
+ sampling from range calculation and avoid repeating item measurements during
32
+ unchanged scroll frames. Scroll ancestor discovery now follows slots and shadow hosts.
33
+
34
+ Breaking: `first` and `last` are read-only computed outputs. Use `scrollToIndex()`
35
+ for navigation and read `range` for rendering instead of assigning output values.
36
+ Virtualization requires uniform line pitch and capacity in sequential DOM order;
37
+ detected unsupported layouts render the full collection. Set `items-per-line`
38
+ for ambiguous uniform grid capacity, or remove it to restore automatic inference.
39
+ Numeric inputs now normalize invalid values and floor integer configuration.
40
+
41
+ ### Patch Changes
42
+
43
+ - 5c006de: Ship component CSS minified. Package builds now run the CSS in Lit `css` styles
44
+ and light-DOM structural styles through Lightning CSS, removing comments and
45
+ whitespace while keeping source maps that resolve to each template. Rendered
46
+ styles are unchanged.
47
+
48
+ `@rcarls/rc-common` adds `cssText`, an identity tag that marks a plain CSS
49
+ string for minification. `rc-chip`, `rc-disclosure`, and `rc-accordion` now
50
+ depend on `@rcarls/rc-common` for it.
51
+
52
+ - 0c9d563: Re-resolve the writing direction when a `dir` attribute changes, and at the
53
+ start of every `scrollToIndex` call, so an inline-axis scroller keeps the
54
+ right range and scrolls to the right item after a page switches direction.
55
+ - 16420f9: Count items per line from where items render instead of from the grid's
56
+ track count, so a collection whose items span several tracks, such as a
57
+ shelf of cards aligned through subgrid across its rows, windows one item per
58
+ line instead of one per track.
59
+ - 7c1c7c4: Keep the rendered window on screen under CSS `zoom`, such as an app-wide
60
+ interface size set on the root. The view position, scrollport size, and line
61
+ pitch were read in viewport pixels but the spacers were written in the host's
62
+ own CSS pixels, so the window drifted off screen by the zoom error as the list
63
+ scrolled, leaving a growing blank gap. All geometry is now converted to host
64
+ pixels, and `scrollToIndex()` scrolls in the scroll container's own pixels.
65
+ - Updated dependencies [e3dfa59]
66
+ - Updated dependencies [50d5610]
67
+ - Updated dependencies [9ee769c]
68
+ - Updated dependencies [1179f24]
69
+ - Updated dependencies [595fe37]
70
+ - Updated dependencies [38cd00c]
71
+ - Updated dependencies [5c006de]
72
+ - Updated dependencies [a6553ff]
73
+ - Updated dependencies [2205478]
74
+ - Updated dependencies [4341311]
75
+ - Updated dependencies [899bb5e]
76
+ - Updated dependencies [25fcfe0]
77
+ - Updated dependencies [51f6403]
78
+ - Updated dependencies [9caca6b]
79
+ - Updated dependencies [b764a3c]
80
+ - Updated dependencies [54d9ead]
81
+ - Updated dependencies [b9175e9]
82
+ - Updated dependencies [c8b762b]
83
+ - Updated dependencies [55e1e7f]
84
+ - Updated dependencies [f1ca82d]
85
+ - Updated dependencies [b87f27b]
86
+ - Updated dependencies [32ebead]
87
+ - Updated dependencies [bfefedd]
88
+ - Updated dependencies [c130173]
89
+ - Updated dependencies [11680b6]
90
+ - Updated dependencies [223d36c]
91
+ - Updated dependencies [7b91a44]
92
+ - Updated dependencies [aa04ead]
93
+ - Updated dependencies [ac65b5b]
94
+ - Updated dependencies [afcfef8]
95
+ - Updated dependencies [11ef1ad]
96
+ - @rcarls/rc-common@0.7.0
package/README.md CHANGED
@@ -1,8 +1,167 @@
1
1
  # @rcarls/rc-virtual-scroller
2
2
 
3
- This version (`0.0.0`) is a placeholder, published only to register this package name on
4
- npm so a Trusted Publisher can be configured for it before any real release. It contains no code.
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
5
 
6
- Do not install or depend on this version. The real package ships in a later version, published
7
- automatically through this repository's normal release pipeline once Trusted Publishing is
8
- configured.
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
+ Virtualization supports sequential DOM-order collections with **uniform line
75
+ pitch and capacity**; the final line may be partial. Use ordinary lists,
76
+ shelves without wrapping, regular grids, or uniform numeric grid spans. Masonry,
77
+ variable-height lines, dense placement, and reordered collections are outside
78
+ this contract. When a sampled layout is demonstrably unsupported, the component
79
+ reports the whole collection, removes its spacers, and warns in development.
80
+
81
+ Automatic grid measurement reads resolved tracks and their gaps, so differently
82
+ aligned items in the same track do not become separate lines. Uniform spans,
83
+ including `1 / -1`, count as items rather than individual tracks. Container
84
+ queries and `auto-fill` remain authoritative.
85
+
86
+ For ambiguous uniform grid placement, set `items-per-line` to the number of
87
+ items in each line. The override controls capacity, not pitch or CSS placement;
88
+ it does not enable virtualization of variable-height layouts. Remove the attribute,
89
+ or assign `itemsPerLine = 0`, to restore automatic inference.
90
+
91
+ ```html
92
+ <rc-virtual-scroller axis="inline" count="500" item-size="160" items-per-line="1">
93
+ <ul class="shelf">
94
+ <!-- One card per column, spanning named row tracks. -->
95
+ </ul>
96
+ </rc-virtual-scroller>
97
+ ```
98
+
99
+ `count` is the true total. `item-size` estimates line pitch until it can be
100
+ measured; it never overrides measured geometry. `overscan` defaults to two
101
+ extra lines at each viewport edge. A one-line slice retains its established
102
+ geometry instead of reverting to a contradictory track-count estimate.
103
+
104
+ Numeric inputs are normalized: `count` and `items-per-line` are floored
105
+ nonnegative integers with a fallback of zero; `overscan` is floored with a
106
+ fallback of two for negative values, infinity, or NaN. Zero, negative, or invalid
107
+ `item-size` becomes zero. Without a usable pitch the full collection is
108
+ reported so it can be measured.
109
+
110
+ `rc-virtual-scroller-range` reports the effective `itemsPerLine`, `lineSize`,
111
+ and `measured` (whether pitch comes from real layout). `first`, `last`, and
112
+ `range` are read-only outputs. The `first` and `last` attributes report the
113
+ computed state; author writes do not control the window.
114
+
115
+ The nearest scrolling ancestor is found through slots and shadow hosts.
116
+ Document scrolling and viewport resizing are supported. Set `scrollTarget`
117
+ when the intended scrollport differs from the automatically resolved ancestor.
118
+ Resizing the scrollport fills newly visible space even when the host itself
119
+ does not resize. A pane hidden with `display: none` retains its mounted slice
120
+ and geometry until layout becomes available again.
121
+
122
+ Call `measure()` after changes that observers cannot see, such as a stylesheet
123
+ writing-mode change that preserves logical size, a font/theme change that only
124
+ affects item internals, or repositioning the collection without resizing it.
125
+ Consumers should commit the requested slice promptly; after an asynchronous
126
+ render commit, call `measure()` if the container's children and size did not
127
+ change.
128
+
129
+ `scrollToIndex(index, { align, behavior })` uses the current line pitch.
130
+ Alignment is `start` (default), `center`, `end`, or `nearest`. Finite
131
+ indices are floored and clamped; infinity and NaN are ignored.
132
+ `disabled` reports the full collection with zero spacers.
133
+
134
+ To migrate code that assigned `first` or `last`, use `scrollToIndex()`
135
+ for navigation and read `range` for rendering. Supply `items-per-line`
136
+ when a uniform grid's placement cannot be inferred.
137
+
138
+ ## Accessibility
139
+
140
+ A virtualized set must still tell assistive technology how big it really is,
141
+ because the DOM no longer says so. The element does not write these for you:
142
+ the roles belong to your markup, and guessing at them would fight a container
143
+ that manages its own rows.
144
+
145
+ - For a list, put `aria-setsize` (the true `count`) and `aria-posinset` (the
146
+ item's real index, not its position in the rendered slice) on each item.
147
+ - For a grid, use `aria-rowcount` / `aria-rowindex`, and
148
+ `aria-colcount` / `aria-colindex` where columns are also virtualized.
149
+ - Set `aria-busy="true"` on the container while a batch is being swapped in, as
150
+ the [WAI-ARIA APG feed pattern](https://www.w3.org/WAI/ARIA/apg/patterns/feed/)
151
+ describes.
152
+
153
+ The one thing the element does handle is focus. Unmounting the focused element
154
+ moves focus to `<body>` with no error and no visible cause, which is how a
155
+ keyboard user silently loses their place. The reported range is always widened
156
+ to include the focused item, contiguously, so your render stays a plain slice;
157
+ it collapses again as soon as focus moves. Scrolling a long way while holding
158
+ focus therefore renders a larger range on purpose.
159
+
160
+ The element sets `overflow-anchor: none` on itself. Browser scroll anchoring
161
+ exists to hold the reading position when content above the viewport changes
162
+ size, which is what this element does every frame, so leaving it on makes the
163
+ two fight and the scroll position drift.
164
+
165
+ Import `@rcarls/rc-virtual-scroller` to use the class without registering it, or
166
+ import `@rcarls/rc-virtual-scroller/define` to register
167
+ `<rc-virtual-scroller>`.