@onekeyfe/react-native-pager-view 6.7.0-alpha.324 → 6.7.0-alpha.335
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/README.md +9 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +2 -2
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerViewManager.kt +2 -2
- package/docs/SPEC.md +107 -6
- package/ios/RNCCollapsiblePagerViewComponentView.mm +341 -23
- package/ios/RNCNativeScrollerComponentView.mm +30 -5
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +124 -0
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +186 -1
- package/ios/tests/RNCCollapsiblePagerRefreshControlTests.mm +50 -0
- package/ios/tests/RNCNativeScrollerTests.mm +39 -0
- package/lib/module/CollapsiblePagerView.js +16 -7
- package/lib/module/CollapsiblePagerView.web.js +428 -37
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +1 -1
- package/lib/module/NativeScroller.js +2 -2
- package/lib/module/NativeScroller.web.js +16 -3
- package/lib/module/NativeScrollerNativeComponent.ts +1 -1
- package/lib/module/ScrollEdgeEffect.js +8 -0
- package/lib/module/WebCollapsiblePagerPage.js +182 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.native.js +9 -0
- package/lib/module/index.web.js +3 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +8 -5
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +66 -4
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/NativeScroller.d.ts +3 -2
- package/lib/typescript/src/NativeScrollerNativeComponent.d.ts +1 -1
- package/lib/typescript/src/ScrollEdgeEffect.d.ts +5 -0
- package/lib/typescript/src/WebCollapsiblePagerPage.d.ts +42 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.native.d.ts +13 -0
- package/lib/typescript/src/index.web.d.ts +5 -0
- package/package.json +6 -4
- package/src/CollapsiblePagerView.tsx +43 -11
- package/src/CollapsiblePagerView.web.tsx +640 -50
- package/src/CollapsiblePagerViewNativeComponent.ts +1 -1
- package/src/NativeScroller.tsx +6 -4
- package/src/NativeScroller.web.tsx +24 -2
- package/src/NativeScrollerNativeComponent.ts +1 -1
- package/src/ScrollEdgeEffect.ts +4 -0
- package/src/WebCollapsiblePagerPage.tsx +258 -0
- package/src/index.native.tsx +30 -0
- package/src/index.tsx +6 -0
- package/src/index.web.tsx +6 -0
package/README.md
CHANGED
|
@@ -67,6 +67,15 @@ Web scroll child can opt in by exposing a DOM element with
|
|
|
67
67
|
`data-collapsible-pager-scroll`. CSS scroll timelines drive header/sticky
|
|
68
68
|
movement, so React is not updated on each vertical scroll frame.
|
|
69
69
|
|
|
70
|
+
On Web, `WebCollapsiblePagerView` is an explicit root export of the existing Web
|
|
71
|
+
pager. It measures Header and sticky content when their heights are omitted.
|
|
72
|
+
`isActive` describes route visibility; the pager preserves a pending scroll
|
|
73
|
+
target across a short or temporarily hidden page and retries when real content
|
|
74
|
+
geometry becomes ready. `useWebCollapsiblePagerPage()` exposes the selected
|
|
75
|
+
page's scroll owner, visible metrics, content registration and pending target
|
|
76
|
+
to descendants. These Web-only APIs require a DOM when mounted. Native callers
|
|
77
|
+
continue to use `CollapsiblePagerView`.
|
|
78
|
+
|
|
70
79
|
On iOS and Android, `nativeTabBar` renders the tab bar natively and
|
|
71
80
|
`onNativeTabPress` reports presses. By default, adjacent tab presses animate and
|
|
72
81
|
non-adjacent presses jump directly to the target without passing intermediate
|
|
@@ -207,8 +207,8 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
// The scroll-edge effect and external overlay are UIKit-only.
|
|
210
|
-
@ReactProp(name = "
|
|
211
|
-
override fun
|
|
210
|
+
@ReactProp(name = "topScrollEdgeEffect")
|
|
211
|
+
override fun setTopScrollEdgeEffect(view: CollapsiblePagerHost?, value: String?) = Unit
|
|
212
212
|
@ReactProp(name = "topOverlayColorScheme")
|
|
213
213
|
override fun setTopOverlayColorScheme(view: CollapsiblePagerHost?, value: String?) = Unit
|
|
214
214
|
@ReactProp(name = "topOverlayHeight", defaultDouble = 0.0)
|
|
@@ -49,8 +49,8 @@ class NativeScrollerViewManager : ViewGroupManager<NativeScrollerView>(),
|
|
|
49
49
|
override fun setContentWidth(view: NativeScrollerView, value: Double) = view.setContentSize(width = view.dip(value))
|
|
50
50
|
@ReactProp(name = "contentHeight")
|
|
51
51
|
override fun setContentHeight(view: NativeScrollerView, value: Double) = view.setContentSize(height = view.dip(value))
|
|
52
|
-
@ReactProp(name = "
|
|
53
|
-
override fun
|
|
52
|
+
@ReactProp(name = "topScrollEdgeEffect")
|
|
53
|
+
override fun setTopScrollEdgeEffect(view: NativeScrollerView, value: String?) = Unit
|
|
54
54
|
@ReactProp(name = "topOverlayHeight", defaultDouble = 0.0)
|
|
55
55
|
override fun setTopOverlayHeight(view: NativeScrollerView, value: Double) = Unit
|
|
56
56
|
@ReactProp(name = "scrollEnabled", defaultBoolean = true)
|
package/docs/SPEC.md
CHANGED
|
@@ -7,20 +7,39 @@ scroll-edge props.
|
|
|
7
7
|
## iOS 26 top scroll edge overlay
|
|
8
8
|
|
|
9
9
|
`CollapsiblePagerView` and standalone `NativeScroller` accept the optional
|
|
10
|
-
`topScrollEdgeEffect=
|
|
10
|
+
`topScrollEdgeEffect={ScrollEdgeEffect.Hard}` or `ScrollEdgeEffect.Soft` with a
|
|
11
|
+
fixed `topOverlay` React child. `ScrollEdgeEffect` is an exported string enum
|
|
12
|
+
(`Hard = "hard"`, `Soft = "soft"`); the corresponding string literals remain
|
|
13
|
+
valid prop values. Both the style and overlay are
|
|
11
14
|
disabled by default. On iOS 26 or newer, a local overlay remains fixed at the
|
|
12
15
|
top of the viewport while the owned vertical `UIScrollView` can draw behind it.
|
|
13
16
|
The component measures the overlay's Fabric layout height and owns the
|
|
14
|
-
corresponding top content inset.
|
|
17
|
+
corresponding top content inset.
|
|
18
|
+
For callers with a known initial height, `topOverlayHeightHint` reserves that
|
|
19
|
+
height on the first frame after the overlay is enabled, before Fabric delivers
|
|
20
|
+
`onLayout`. The measured height replaces the hint, and disabling the overlay
|
|
21
|
+
clears the measurement so a later enablement can use a new hint. The hint does
|
|
22
|
+
not enable the effect or reserve an inset without an active local overlay.
|
|
23
|
+
This uses the existing native `topOverlayHeight` prop without changing the
|
|
24
|
+
native interface. For native smooth local Hard mode, a complete Fabric mount
|
|
25
|
+
attaches the overlay slot synchronously before `didMount` returns; incomplete
|
|
26
|
+
slots retain the deferred fallback. It binds UIKit's
|
|
15
27
|
`UIScrollEdgeElementContainerInteraction` to that exact scroll view and selects
|
|
16
|
-
the
|
|
28
|
+
the requested top edge style. Hard has UIKit's dividing line; Soft has its
|
|
29
|
+
gradual blurred transition. A pager owns the effect and inset for its current page;
|
|
17
30
|
its nested NativeList or NativeScroller must not opt into another top overlay.
|
|
18
31
|
Invisible, noninteractive native labels let UIKit recognize the React-drawn
|
|
19
32
|
overlay and sticky header as scroll-edge elements. The pager does not add an
|
|
20
|
-
auxiliary full-area glass
|
|
33
|
+
auxiliary full-area glass. It clips scrolling assets above
|
|
21
34
|
the fixed overlay boundary; during horizontal transitions it clips its owned
|
|
22
35
|
visible page hosts below the current sticky boundary so text cannot pass in
|
|
23
36
|
front of the fixed controls. Masked assets must not intercept their hit targets.
|
|
37
|
+
On iOS 27 or newer, a local smooth Hard pager with a valid shared-header mask
|
|
38
|
+
fades a bottommost overlay layer using the resolved opaque pager or ancestor
|
|
39
|
+
theme color as the real header collapses, without hard-coded colors or changing
|
|
40
|
+
UIKit's Hard style, owner or interactions. During temporary horizontal owner
|
|
41
|
+
transitions the layer holds its last opacity until geometry is valid again;
|
|
42
|
+
disabling the local overlay, changing style or recycling removes it.
|
|
24
43
|
|
|
25
44
|
For an iOS 26 pager whose fixed header is rendered by a sibling in the same
|
|
26
45
|
React surface, `externalTopOverlayTag` may identify that header's native view.
|
|
@@ -28,7 +47,7 @@ The pager weakly observes its geometry in the same window, retaining its own
|
|
|
28
47
|
noninteractive native proxy for UIKit recognition without reparenting or
|
|
29
48
|
modifying the React header. The measured external header bottom supplies the
|
|
30
49
|
top inset and sticky anchor. A local `topOverlay` takes precedence. The tag
|
|
31
|
-
alone never enables the effect: `topScrollEdgeEffect
|
|
50
|
+
alone never enables the effect: either `topScrollEdgeEffect` enum value controls the
|
|
32
51
|
interaction, while valid external geometry can reserve the top inset before
|
|
33
52
|
the effect is enabled. Before the tag and height are ready, the caller keeps
|
|
34
53
|
its existing layout; an unresolved native tag has zero external height. An
|
|
@@ -47,7 +66,7 @@ When a smooth shared header reaches the overlay boundary, the existing sticky
|
|
|
47
66
|
React and native tab views move together into a view pinned to the active
|
|
48
67
|
scroll view. Their identities, scroll-view gesture ancestry and hit targets
|
|
49
68
|
remain intact; the collapsible header stays in the scrolling header host.
|
|
50
|
-
Without a local or external overlay,
|
|
69
|
+
Without a local or external overlay, either scroll-edge style may protect
|
|
51
70
|
only the genuinely pinned sticky header; it must not consume a page as a
|
|
52
71
|
synthetic overlay slot or change the collapsible banner distance.
|
|
53
72
|
Changing pages, replacing the active list or recycling returns those views to
|
|
@@ -57,6 +76,8 @@ The measured overlay height is excluded from the collapsible header distance:
|
|
|
57
76
|
overlay. Selection, cancellation, reuse and disposal rebind or release the
|
|
58
77
|
interaction and restore any prior scroll-edge style. Native scroll/refresh
|
|
59
78
|
coordination continues on the main thread without per-frame JavaScript work.
|
|
79
|
+
Refresh retains the pager-owned `overlay + header + sticky` top inset but offsets
|
|
80
|
+
the indicator by `header + sticky`, so its spinner begins below the fixed overlay.
|
|
60
81
|
|
|
61
82
|
On iOS before 26, the external tag is not forwarded to native. On iOS before
|
|
62
83
|
26, Android and Web the new props have no scroll-edge effect.
|
|
@@ -69,6 +90,27 @@ Acceptance requires real iOS 26 scrolling, partial collapse, short/empty page,
|
|
|
69
90
|
refresh, page transition/cancellation, dynamic tabs and light/dark checks;
|
|
70
91
|
source and build checks alone do not establish visual correctness.
|
|
71
92
|
|
|
93
|
+
`CollapsiblePagerView` paints a cover at each owned
|
|
94
|
+
fixed-overlay or pinned-sticky boundary with one physical pixel of the nearest
|
|
95
|
+
opaque ancestor background color (system background if none is available).
|
|
96
|
+
These native layers do not receive touches, change insets, or clip glass shadows.
|
|
97
|
+
They are removed for Soft, disabled/detached effects, and recycling. This is a
|
|
98
|
+
visual workaround using public layer APIs, not a UIKit separator setting. While
|
|
99
|
+
the sticky header is pinned, only the top cover is hidden; it reappears on unpin,
|
|
100
|
+
and the sticky cover and both Hard interactions remain active. Standalone
|
|
101
|
+
NativeScroller and NativeList retain UIKit's unmodified Hard appearance.
|
|
102
|
+
|
|
103
|
+
Style selection crosses Fabric as the enum `none | hard | soft`, defaulting to
|
|
104
|
+
`none`, rather than a hard-effect boolean. Switching Hard ↔ Soft on an attached
|
|
105
|
+
owner updates UIKit without replacing the overlay or changing its inset,
|
|
106
|
+
logical scroll offset, or saved original style. Clearing the prop, detaching,
|
|
107
|
+
or recycling releases the interaction and restores that original style.
|
|
108
|
+
This bridge contract requires a matching native rebuild. Soft selection is
|
|
109
|
+
implemented in the public wrappers and native hosts. Focused JS tests cover
|
|
110
|
+
style forwarding, overlay retention and disabling; UIKit tests cover native
|
|
111
|
+
style switching and restoring the previous style. Rendered iOS acceptance must
|
|
112
|
+
be reported separately from type, codegen and build checks.
|
|
113
|
+
|
|
72
114
|
## Smooth shared-header and per-page body memory
|
|
73
115
|
|
|
74
116
|
With nativeSmoothHeaderScrollEnabled, the header collapse C is shared across all
|
|
@@ -814,3 +856,62 @@ The native Home Spotlight adapter consumes this snapshot in the main UI runtime
|
|
|
814
856
|
Removing a page or clearing the page collection MUST cancel the active horizontal transition and its temporary display snapshots before notifying the adapter. Cancellation MUST NOT rewrite the shared Header collapse or surviving pages' saved body reading memory. The previous observed owner MUST be detached without committing an offset under a shifted page key.
|
|
815
857
|
|
|
816
858
|
An empty adapter MUST reject transition starts and transition completion without coercing an index into an empty range. The selected index uses zero as an empty-state sentinel; nonempty mutations clamp it to the remaining valid range. Readding pages MUST allow a fresh selection and MUST NOT resume a removed transition source. Conformance requires actual Android active-transition → zero-pages → readd/selection regression and remaining-page mutation checks; structural checks and compilation alone do not establish runtime behavior.
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
## Web parent-scroll owner identity
|
|
862
|
+
|
|
863
|
+
Web Header and sticky overlays use the named scroll timeline only when the
|
|
864
|
+
browser supports every CSS property needed for that linkage. Otherwise, the
|
|
865
|
+
active scroll owner's offset drives the same clamped Header collapse in JS:
|
|
866
|
+
`C = min(max(scrollTop, 0), max(headerHeight, 0))`. The fallback keeps the
|
|
867
|
+
existing page owner, insets, body offset memory, and sticky anchor. It updates
|
|
868
|
+
when scrolling, selecting or restoring a page, replacing an owner, or changing
|
|
869
|
+
Header height, and releases its listener when that owner detaches. An inactive
|
|
870
|
+
page cannot move the visible Header. This is a Web-only compatibility path; no
|
|
871
|
+
native behavior or public prop changes.
|
|
872
|
+
When an overlay forwards a vertical wheel or touch scroll to the active owner,
|
|
873
|
+
the owner receives the same internal user-input notification used by route
|
|
874
|
+
restoration to cancel an obsolete pending offset.
|
|
875
|
+
|
|
876
|
+
On Web, an explicitly marked NativeScroller is selected before an implicit NativeList viewport. There is one vertical owner per page; callers using parent-owned NativeList pass that same scroll element as webScrollHost.
|
|
877
|
+
|
|
878
|
+
The existing NativeScroller pagerScrollKey identifies a Web page scroll owner. Changing the key invalidates that page body offset without remounting its React business content. The active owner also resets the shared header collapse and cancels queued old restore/top commands. Inactive owners invalidate their saved body offset without imperative scrolling; selection checks the current identity before restoring. A→B→A identity changes never revive a prior owner offset. Stable keys preserve ordinary page C+B restoration. Current-page top commands continue to affect only the selected page.
|
|
879
|
+
|
|
880
|
+
Identity notifications and DOM owner listeners are internal implementation details, removed when the pager root or owner is replaced/unmounted. No native behavior or public configuration is added.
|
|
881
|
+
|
|
882
|
+
### Web overlay input and keyed-page updates
|
|
883
|
+
|
|
884
|
+
- Header and sticky slots remain overlays: overflow outside the sticky slot may remain visible without adding its portal height to page insets twice.
|
|
885
|
+
- Vertical wheel or touch input over those overlays transfers only to the active page scroll owner when no nested scrollable consumes it. Horizontal controls, editable inputs, and ordinary button/tap behavior retain their own events. Input originating inside the page owner follows native scrolling once.
|
|
886
|
+
- Reordering or removing keyed pages must save the previously configured key and owner, rather than resolving the old selected index against new children. Caller index synchronization preserves keyed body offsets and shared header collapse.
|
|
887
|
+
- For an explicit NativeScroller, Pager chrome insets apply to the existing ScrollView content element, not its viewport. Insets taller than the available window cannot enlarge the scroll viewport. Existing owner/content padding is preserved and restored separately from Pager insets; direct NativeList/page-host fallback retains its prior layout path.
|
|
888
|
+
- The Pager root clips without becoming a programmatically scrollable overflow box. Browser focus and descendant scrollIntoView cannot add a second horizontal page offset outside the selected-page transform.
|
|
889
|
+
|
|
890
|
+
## Web page geometry and route restoration
|
|
891
|
+
|
|
892
|
+
Status: Implemented in Web source and focused tests; browser and native runtime acceptance remain separate.
|
|
893
|
+
|
|
894
|
+
`WebCollapsiblePagerView` is the existing Web `CollapsiblePagerView` class under an explicit root export. Its `isActive` prop defaults to true and represents route visibility, independently of the selected page. The Web-only `useWebCollapsiblePagerPage()` hook returns null outside a Web pager and otherwise exposes `isFocused`, `isRouteActive`, `owner`, `content`, optional `contentHeight`, `width`, `height`, content-relative `scrollTop`, `registerContent`, and read-only `pendingRouteScrollTop`. Native `CollapsiblePagerView`, its bridge, and its props are unchanged. The Web component rejects mounting without a DOM; importing the root or Web module alone must not access DOM globals.
|
|
895
|
+
|
|
896
|
+
Web callers may supply finite nonnegative `headerHeight` and `stickyHeaderHeight`. When omitted or invalid (negative, NaN, or infinite), the SDK measures the natural inner Header and sticky content with `ResizeObserver`; explicit valid values take precedence, including zero. An initial unmeasured zero is not ready for route restoration; a measured empty chrome element may legitimately have zero height. Measurement must not use the constrained slot height as its own input. Height changes update the owned insets before route restoration. Existing explicit-height callers retain their layout path.
|
|
897
|
+
|
|
898
|
+
Each page has one SDK-discovered vertical owner: explicit `NativeScroller`, then implicit NativeList viewport, then page host. Registration accepts a connected content element and optional finite nonnegative explicit height; invalid height metadata is ignored. It does not change DOM layout or make a pending target reachable. A later registration of the same element supersedes an earlier one, and stale cleanup cannot remove it. An explicit-height change schedules geometry measurement even if the element border box is unchanged. Metrics use owner client width; `pinnedBottom = ownerRect.top + max(0, headerHeight - owner.scrollTop) + stickyHeaderHeight`; `visibleTop = max(ownerRect.top, pinnedBottom, contentRect.top if present)`; visible height is `max(0, ownerRect.bottom - visibleTop)` and content-relative scroll top is `max(0, pinnedBottom - contentRect.top)`. Unregistered content falls back to the first owner child. Detached content and callbacks from old owners are ignored. One animation-frame measurement per page coalesces scroll, resize, registration, owner configuration, and active-page changes. Disposal releases observers, listeners, frames, and subscriptions.
|
|
899
|
+
|
|
900
|
+
On active-to-inactive transition, the Web pager freezes the selected logical React page key, `pagerScrollKey` identity, actual owner generation, and last valid raw DOM top. Inactive scroll/geometry changes cannot replace the snapshot. A second blur of the same pending identity preserves the original target. On focus, owner, content, chrome, or inset changes, the pager retries without a timer only when the route is active, that exact key/identity/owner remains selected and connected, the viewport has positive height, the pager has configured the expected insets, and real `scrollHeight - clientHeight` reaches the target. Short content keeps the target pending. Restoration clears pending before one instant scroll and synchronizes the existing shared Header C and per-page body B memory. An idempotent Web `restoreScrollPosition()` returns false while inactive or not ready and true when no target remains or it applies; normal callers need no polling.
|
|
901
|
+
|
|
902
|
+
Valid vertical wheel, scroll keys, scrollbar drag, overlay-forwarded input, accepted NativeList commands, and explicit page-top/sticky-top commands cancel pending route intent through the existing SDK takeover path. As in the prior Web app adapter, any owner `pointerdown` or `touchstart`, including a child target, cancels only route pending; this does not newly commit or clear SDK C+B memory. Geometry-only scroll/resize/scrollend cannot cancel intent. Valid same-offset commands cancel it; invalid or stale commands do not. A matching route target takes priority over automatic tab C+B restoration. Selection of a different key, owner identity reset (including A→B→A), genuine DOM owner replacement, or removal cancels pending; a same-key index reorder preserves it. A same-commit blur and Activity/Offscreen effect disconnect captures the current route target before releasing the owner; repeated disconnects preserve an existing pending target. A temporary React ref null or Activity/Offscreen effect disconnect followed by the identical connected owner preserves the logical route target and owner generation while releasing all observers, listeners, frames, and DOM configuration during disconnect. Restoration is unavailable while disconnected; reconnect remeasures automatic chrome before applying pending. A truly removed pager instance cannot transfer its pending target to a new instance. Older queued tab/top callbacks must validate generation before writing after route restoration or cancellation. The app owns navigation focus and business tab names; the SDK never infers them from escaped React child keys.
|
|
903
|
+
|
|
904
|
+
Platform matrix: Web owns this DOM geometry, registration, route pending, and explicit Web export. iOS and Android keep native scrolling, restoration, and page coordination documented above, with no new prop, native bridge call, JS heap sharing, or process resource. The UI main runtime owns Web state; background runtimes do not deserialize it. Source/type tests establish only Web contract implementation, not browser rendering or native device behavior. Acceptance requires real Web/Desktop route blur, short content then growth, user takeover, dynamic chrome, key reset, and Home/Market scroll regressions.
|
|
905
|
+
|
|
906
|
+
## Native package entry isolation
|
|
907
|
+
|
|
908
|
+
The Native package entry exports the existing Native PagerView,
|
|
909
|
+
CollapsiblePagerView, NativeScroller, usePagerView and ScrollEdgeEffect APIs.
|
|
910
|
+
Native package resolution MUST NOT evaluate the Web pager or Web page-context
|
|
911
|
+
modules. The react-native field and conditional export resolve to a real Native
|
|
912
|
+
entry; the browser entry retains the Web runtime APIs. The generic declaration
|
|
913
|
+
entry preserves the existing shared Web value/type API for TypeScript callers.
|
|
914
|
+
This separates package initialization in the Native UI main runtime; it does not
|
|
915
|
+
add a bridge, share JS heaps with background, or change Native scroll commands.
|
|
916
|
+
Acceptance includes the actual Native dependency graph and unchanged startup
|
|
917
|
+
budgets, Web runtime/type exports, and package source/module/declaration entries.
|