@onekeyfe/react-native-pager-view 6.7.0-alpha.435 → 6.7.0-alpha.445
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 +16 -0
- package/android/build.gradle +1 -0
- package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +135 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +88 -12
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +442 -15
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +11 -1
- package/android/src/main/java/com/reactnativepagerview/event/NativeHeaderPressEvent.kt +8 -0
- package/docs/SPEC.md +298 -3
- package/ios/RNCCollapsiblePagerViewComponentView.mm +834 -20
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +61 -0
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +22 -0
- package/lib/module/CollapsiblePagerView.js +37 -5
- package/lib/module/CollapsiblePagerView.web.js +519 -6
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +6 -0
- package/lib/module/NativeScrollerNativeComponent.ts +0 -1
- package/lib/typescript/src/CollapsiblePagerView.d.ts +31 -2
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +44 -1
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +11 -0
- package/lib/typescript/src/NativeScroller.d.ts +2 -2
- package/package.json +3 -2
- package/src/CollapsiblePagerView.tsx +68 -5
- package/src/CollapsiblePagerView.web.tsx +464 -5
- package/src/CollapsiblePagerViewNativeComponent.ts +6 -0
- package/src/NativeScroller.tsx +2 -3
- package/src/NativeScrollerNativeComponent.ts +0 -1
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { createNamedIcon } from "@onekeyfe/react-native-image/icon/dom";
|
|
4
|
+
import type { CollapsiblePagerNativeTabBarConfig, CollapsiblePagerToolbarItem, CollapsiblePagerToolbarPress, CollapsiblePagerViewOnNativeTabPressEvent } from "./CollapsiblePagerView";
|
|
5
|
+
export type { CollapsiblePagerNativeTabBarConfig, CollapsiblePagerNativeTabBarItem, CollapsiblePagerNativeTabBarStyle, CollapsiblePagerToolbarItem, CollapsiblePagerToolbarPress } from "./CollapsiblePagerView";
|
|
6
|
+
import { I18nManager, Platform, processColor, StyleSheet, View } from "react-native";
|
|
4
7
|
import type * as ReactNative from "react-native";
|
|
5
8
|
|
|
6
9
|
import { WebCollapsiblePagerPage } from "./WebCollapsiblePagerPage";
|
|
@@ -66,6 +69,10 @@ export interface CollapsiblePagerViewProps
|
|
|
66
69
|
| "retainedPages"
|
|
67
70
|
| "layoutDirection"
|
|
68
71
|
> {
|
|
72
|
+
nativeTabBar?: CollapsiblePagerNativeTabBarConfig;
|
|
73
|
+
nativeTabPressAnimationEnabled?: boolean;
|
|
74
|
+
onNativeTabPress?: (event: CollapsiblePagerViewOnNativeTabPressEvent) => void;
|
|
75
|
+
onNativeToolbarPress?: (event: ReactNative.NativeSyntheticEvent<CollapsiblePagerToolbarPress>) => void;
|
|
69
76
|
header: React.ReactNode;
|
|
70
77
|
stickyHeader: React.ReactNode;
|
|
71
78
|
headerHeight?: number;
|
|
@@ -188,6 +195,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
188
195
|
|
|
189
196
|
private root: HTMLElement | null = null;
|
|
190
197
|
private track: HTMLElement | null = null;
|
|
198
|
+
private tabProgress: number | null = null;
|
|
199
|
+
private tabProgressFrame: number | null = null;
|
|
200
|
+
private tabProgressGeneration = 0;
|
|
201
|
+
private tabButtons = new Map<string, HTMLButtonElement>();
|
|
191
202
|
private headerSlot: HTMLElement | null = null;
|
|
192
203
|
private stickySlot: HTMLElement | null = null;
|
|
193
204
|
private cssTimelineSupported = false;
|
|
@@ -236,6 +247,7 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
236
247
|
key: string;
|
|
237
248
|
}> | null = null;
|
|
238
249
|
private transitionTimer: ReturnType<typeof setTimeout> | null = null;
|
|
250
|
+
private transitionGeneration = 0;
|
|
239
251
|
private pageScrollState: OnPageScrollStateChangedEventData["pageScrollState"] =
|
|
240
252
|
"idle";
|
|
241
253
|
private configuredScrollElement: ConfiguredScrollElement | null = null;
|
|
@@ -290,6 +302,9 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
290
302
|
this.scheduleScrollConfiguration();
|
|
291
303
|
this.syncFallbackHeader();
|
|
292
304
|
this.notifyMountedPagesChanged();
|
|
305
|
+
this.syncToolbar();
|
|
306
|
+
this.tabProgress = this.state.selectedPage;
|
|
307
|
+
this.syncTabColors();
|
|
293
308
|
this.emitDiagnostics("mounted");
|
|
294
309
|
}
|
|
295
310
|
|
|
@@ -359,6 +374,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
359
374
|
this.scheduleScrollConfiguration();
|
|
360
375
|
this.syncFallbackHeader();
|
|
361
376
|
this.notifyMountedPagesChanged();
|
|
377
|
+
this.syncToolbar();
|
|
378
|
+
if (previousProps.isActive === false && this.props.isActive !== false) this.readTabProgress();
|
|
379
|
+
if (this.props.isActive === false || !this.tabColorWeights()) this.cancelTabProgressFrame();
|
|
380
|
+
this.syncTabColors();
|
|
362
381
|
}
|
|
363
382
|
|
|
364
383
|
componentWillUnmount() {
|
|
@@ -366,6 +385,7 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
366
385
|
const routeTarget = this.captureRouteTarget(this.props);
|
|
367
386
|
if (routeTarget) this.setRouteTarget(routeTarget);
|
|
368
387
|
this.disposed = true;
|
|
388
|
+
this.setToolbarSlot(null);
|
|
369
389
|
this.selectionRestoreToken += 1;
|
|
370
390
|
this.cancelPendingTopFrame();
|
|
371
391
|
this.savePageOffset(this.state.selectedPage);
|
|
@@ -411,6 +431,7 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
411
431
|
|
|
412
432
|
private observeChrome() {
|
|
413
433
|
this.chromeObserver = new ResizeObserver(this.scheduleChromeMeasurement);
|
|
434
|
+
if (this.root) this.chromeObserver.observe(this.root);
|
|
414
435
|
if (this.headerContent) this.chromeObserver.observe(this.headerContent);
|
|
415
436
|
if (this.stickyContent) this.chromeObserver.observe(this.stickyContent);
|
|
416
437
|
this.scheduleChromeMeasurement();
|
|
@@ -439,6 +460,8 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
439
460
|
this.measuredStickyHeight = nextSticky;
|
|
440
461
|
this.headerMeasured = Boolean(header?.isConnected);
|
|
441
462
|
this.stickyMeasured = Boolean(sticky?.isConnected);
|
|
463
|
+
this.syncToolbar();
|
|
464
|
+
this.syncTabColors();
|
|
442
465
|
if (headerChanged || stickyChanged) {
|
|
443
466
|
this.forceUpdate();
|
|
444
467
|
this.scheduleScrollConfiguration();
|
|
@@ -741,21 +764,32 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
741
764
|
}
|
|
742
765
|
|
|
743
766
|
private finishPageTransition = () => {
|
|
767
|
+
this.transitionGeneration += 1;
|
|
744
768
|
if (this.transitionTimer !== null) {
|
|
745
769
|
clearTimeout(this.transitionTimer);
|
|
746
770
|
this.transitionTimer = null;
|
|
747
771
|
}
|
|
772
|
+
this.readTabProgress();
|
|
773
|
+
this.cancelTabProgressFrame();
|
|
774
|
+
this.syncTabColors();
|
|
748
775
|
this.emitPageScrollState("idle");
|
|
776
|
+
this.syncToolbar();
|
|
749
777
|
};
|
|
750
778
|
|
|
751
779
|
private beginPageTransition() {
|
|
780
|
+
this.suspendToolbar();
|
|
752
781
|
if (this.transitionTimer !== null) clearTimeout(this.transitionTimer);
|
|
782
|
+
const generation = ++this.transitionGeneration;
|
|
753
783
|
this.emitPageScrollState("settling");
|
|
754
|
-
this.transitionTimer = setTimeout(
|
|
784
|
+
this.transitionTimer = setTimeout(() => {
|
|
785
|
+
if (generation === this.transitionGeneration) this.finishPageTransition();
|
|
786
|
+
}, 320);
|
|
755
787
|
}
|
|
756
788
|
|
|
757
789
|
private onTrackTransitionEnd = (event: TransitionEvent) => {
|
|
758
790
|
if (event.target === this.track && event.propertyName === "transform") {
|
|
791
|
+
this.readTabProgress();
|
|
792
|
+
if (this.tabColorWeights() && this.tabProgress !== null && Math.abs(this.tabProgress - this.state.selectedPage) > 0.001) return;
|
|
759
793
|
this.finishPageTransition();
|
|
760
794
|
}
|
|
761
795
|
};
|
|
@@ -763,11 +797,120 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
763
797
|
private setTrack = (node: unknown) => {
|
|
764
798
|
const track = webElement(node);
|
|
765
799
|
if (track === this.track) return;
|
|
800
|
+
this.cancelTabProgressFrame();
|
|
766
801
|
this.track?.removeEventListener("transitionend", this.onTrackTransitionEnd);
|
|
767
802
|
this.track = track;
|
|
768
803
|
this.track?.addEventListener("transitionend", this.onTrackTransitionEnd);
|
|
769
804
|
};
|
|
770
805
|
|
|
806
|
+
private cancelTabProgressFrame() {
|
|
807
|
+
this.tabProgressGeneration += 1;
|
|
808
|
+
if (this.tabProgressFrame !== null) cancelAnimationFrame(this.tabProgressFrame);
|
|
809
|
+
this.tabProgressFrame = null;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
private readTabProgress() {
|
|
813
|
+
const track = this.track;
|
|
814
|
+
const width = this.root?.getBoundingClientRect().width ?? 0;
|
|
815
|
+
if (!track?.isConnected || width <= 0) return null;
|
|
816
|
+
const transform = track.ownerDocument.defaultView?.getComputedStyle(track).transform;
|
|
817
|
+
const matrix = transform?.match(/^matrix(3d)?\(([^)]+)\)$/);
|
|
818
|
+
const offset = matrix ? Number(matrix[2].split(",")[matrix[1] ? 12 : 4]) : transform === "none" ? 0 : NaN;
|
|
819
|
+
if (!Number.isFinite(offset)) return null;
|
|
820
|
+
this.tabProgress = Math.min(Math.max(0, -offset / width), Math.max(0, this.pages().length - 1));
|
|
821
|
+
return this.tabProgress;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
private startTabProgressFrames() {
|
|
825
|
+
this.cancelTabProgressFrame();
|
|
826
|
+
if (!this.tabColorWeights() || typeof requestAnimationFrame !== "function") return;
|
|
827
|
+
const track = this.track;
|
|
828
|
+
const root = this.root;
|
|
829
|
+
const width = root?.getBoundingClientRect().width ?? 0;
|
|
830
|
+
if (!track?.isConnected || !root?.isConnected || width <= 0 || this.props.isActive === false) return;
|
|
831
|
+
const generation = this.tabProgressGeneration;
|
|
832
|
+
const selection = this.selectionRestoreToken;
|
|
833
|
+
const keys = JSON.stringify(this.pages().map(pageKey));
|
|
834
|
+
const owner = this.pageScrollElement(this.state.selectedPage);
|
|
835
|
+
const sample = () => {
|
|
836
|
+
if (generation !== this.tabProgressGeneration || this.disposed) return;
|
|
837
|
+
this.tabProgressFrame = null;
|
|
838
|
+
if (this.track !== track || this.root !== root || !track.isConnected || !root.isConnected ||
|
|
839
|
+
this.props.isActive === false || selection !== this.selectionRestoreToken ||
|
|
840
|
+
keys !== JSON.stringify(this.pages().map(pageKey)) || owner !== this.pageScrollElement(this.state.selectedPage) ||
|
|
841
|
+
width !== root.getBoundingClientRect().width || !this.tabColorWeights()) {
|
|
842
|
+
this.cancelTabProgressFrame();
|
|
843
|
+
this.readTabProgress();
|
|
844
|
+
this.syncTabColors();
|
|
845
|
+
if (this.transitionTimer !== null) this.startTabProgressFrames();
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
this.readTabProgress();
|
|
849
|
+
this.syncTabColors();
|
|
850
|
+
if (this.transitionTimer !== null) this.tabProgressFrame = requestAnimationFrame(sample);
|
|
851
|
+
};
|
|
852
|
+
sample();
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
private tabColorWeights() {
|
|
856
|
+
const config = this.props.nativeTabBar;
|
|
857
|
+
if (!config?.controlled || config.style?.variant !== "text" || this.tabProgress === null) return null;
|
|
858
|
+
const keys: string[] = [];
|
|
859
|
+
React.Children.forEach(this.props.children, child => {
|
|
860
|
+
if (child !== null && child !== undefined && typeof child !== "boolean") keys.push(pageKey(child, keys.length));
|
|
861
|
+
});
|
|
862
|
+
const itemKeys = config.items.map(item => item.key);
|
|
863
|
+
if (!keys.length || !keys.includes(config.selectedKey ?? "") || new Set(keys).size !== keys.length ||
|
|
864
|
+
new Set(itemKeys).size !== itemKeys.length || keys.some(key => !itemKeys.includes(key))) return null;
|
|
865
|
+
const progress = Math.min(Math.max(0, this.tabProgress), keys.length - 1);
|
|
866
|
+
const source = Math.floor(progress);
|
|
867
|
+
const destination = Math.min(source + 1, keys.length - 1);
|
|
868
|
+
const fraction = progress - source;
|
|
869
|
+
return new Map(keys.map((key, index) => [key, index === source ? 1 - fraction : index === destination ? fraction : 0]));
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
private tabFontOwnerKey(weights: Map<string, number> | null) {
|
|
873
|
+
const config = this.props.nativeTabBar;
|
|
874
|
+
const semantic = config?.controlled ? config.selectedKey : config?.items[this.state.selectedPage]?.key;
|
|
875
|
+
if (!weights || this.tabProgress === null) return semantic;
|
|
876
|
+
const keys = Array.from(weights.keys());
|
|
877
|
+
const progress = Math.min(Math.max(0, this.tabProgress), keys.length - 1);
|
|
878
|
+
return keys[Math.floor(progress + 0.5)];
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
private tabColor(selected: boolean, weight: number | undefined) {
|
|
882
|
+
const style = this.props.nativeTabBar?.style;
|
|
883
|
+
const active = style?.activeTextColor ?? "#000000";
|
|
884
|
+
const inactive = style?.inactiveTextColor ?? "#666666";
|
|
885
|
+
if (weight === undefined) return String(selected ? active : inactive);
|
|
886
|
+
if (weight <= 0) return String(inactive);
|
|
887
|
+
if (weight >= 1) return String(active);
|
|
888
|
+
const first = processColor(inactive);
|
|
889
|
+
const last = processColor(active);
|
|
890
|
+
if (typeof first !== "number" || typeof last !== "number") return String(selected ? active : inactive);
|
|
891
|
+
const channel = (shift: number) => ((first >>> shift) & 255) * (1 - weight) + ((last >>> shift) & 255) * weight;
|
|
892
|
+
return `rgba(${Math.round(channel(16))}, ${Math.round(channel(8))}, ${Math.round(channel(0))}, ${(channel(24) / 255).toFixed(4)})`;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
private syncTabColors() {
|
|
896
|
+
const weights = this.tabColorWeights();
|
|
897
|
+
const config = this.props.nativeTabBar;
|
|
898
|
+
if (!config) return;
|
|
899
|
+
const selectedKey = config.controlled ? config.selectedKey : config.items[this.state.selectedPage]?.key;
|
|
900
|
+
const fontOwnerKey = this.tabFontOwnerKey(weights);
|
|
901
|
+
for (const [key, button] of this.tabButtons) {
|
|
902
|
+
const fontSelected = key === fontOwnerKey;
|
|
903
|
+
button.style.color = this.tabColor(key === selectedKey, weights ? weights.get(key) ?? 0 : undefined);
|
|
904
|
+
button.style.fontWeight = config.style?.variant === "text" && fontSelected ? "600" : "500";
|
|
905
|
+
const fontFamily = (fontSelected ? config.style?.activeFontFamily ?? config.style?.fontFamily : config.style?.fontFamily) ?? "";
|
|
906
|
+
if (config.controlled && config.style?.variant === "text") {
|
|
907
|
+
button.style.fontFamily = config.style?.fontFamily ?? "";
|
|
908
|
+
const label = button.querySelector<HTMLElement>(".ok-pager-tab-label");
|
|
909
|
+
if (label) label.style.fontFamily = fontFamily;
|
|
910
|
+
} else button.style.fontFamily = fontFamily;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
771
914
|
private pageScrollElement(index: number) {
|
|
772
915
|
const pageHost = this.pageHosts.get(index);
|
|
773
916
|
return (
|
|
@@ -790,7 +933,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
790
933
|
this.root?.removeEventListener("touchend", this.onOverlayTouchEnd);
|
|
791
934
|
this.root?.removeEventListener("touchcancel", this.onOverlayTouchEnd);
|
|
792
935
|
this.overlayTouch = null;
|
|
936
|
+
if (this.root) this.chromeObserver?.unobserve(this.root);
|
|
793
937
|
this.root = root;
|
|
938
|
+
if (root) this.chromeObserver?.observe(root);
|
|
939
|
+
else this.suspendToolbar();
|
|
794
940
|
root?.addEventListener(
|
|
795
941
|
"ok-collapsible-pager-scroll-key-changed",
|
|
796
942
|
this.onScrollOwnerIdentityChanged
|
|
@@ -1191,10 +1337,14 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
1191
1337
|
this.savePageOffset(this.state.selectedPage);
|
|
1192
1338
|
|
|
1193
1339
|
if (animated) this.beginPageTransition();
|
|
1194
|
-
else
|
|
1340
|
+
else {
|
|
1341
|
+
this.finishPageTransition();
|
|
1342
|
+
this.tabProgress = position;
|
|
1343
|
+
}
|
|
1195
1344
|
this.setState(
|
|
1196
1345
|
{ selectedPage: position, animateTransition: animated },
|
|
1197
1346
|
() => {
|
|
1347
|
+
if (animated) this.startTabProgressFrames();
|
|
1198
1348
|
this.scheduleScrollConfiguration();
|
|
1199
1349
|
const restore = () => {
|
|
1200
1350
|
if (
|
|
@@ -1294,6 +1444,7 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
1294
1444
|
this.cancelPendingTopFrame();
|
|
1295
1445
|
this.horizontalTouch = true;
|
|
1296
1446
|
this.emitPageScrollState("dragging");
|
|
1447
|
+
this.suspendToolbar();
|
|
1297
1448
|
}
|
|
1298
1449
|
};
|
|
1299
1450
|
|
|
@@ -1338,9 +1489,317 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
1338
1489
|
if (wasHorizontal) this.finishPageTransition();
|
|
1339
1490
|
};
|
|
1340
1491
|
|
|
1492
|
+
private toolbarSlot: HTMLDivElement | null = null;
|
|
1493
|
+
private toolbarButton: HTMLButtonElement | null = null;
|
|
1494
|
+
private toolbarOwnerKey: string | undefined;
|
|
1495
|
+
private toolbarOwnerEntry: CollapsiblePagerToolbarItem | undefined;
|
|
1496
|
+
private toolbarIconIdentity = "";
|
|
1497
|
+
private toolbarLoadedIcon: SVGSVGElement | null = null;
|
|
1498
|
+
private toolbarPendingIdentity = "";
|
|
1499
|
+
private toolbarReadyIcon: SVGSVGElement | null = null;
|
|
1500
|
+
private toolbarFailedIdentity = "";
|
|
1501
|
+
private toolbarAnimation: Animation | null = null;
|
|
1502
|
+
private toolbarPresence = false;
|
|
1503
|
+
private toolbarPresenceInterrupted = false;
|
|
1504
|
+
private toolbarImage: HTMLImageElement | null = null;
|
|
1505
|
+
private toolbarGeneration = 0;
|
|
1506
|
+
private toolbarTouchKey: string | null | undefined;
|
|
1507
|
+
|
|
1508
|
+
private ownsSettledToolbar() {
|
|
1509
|
+
return this.props.nativeTabBar?.controlled === true && this.props.nativeTabBar.toolbar !== undefined;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
private toolbarCanCommit() {
|
|
1513
|
+
if (!this.ownsSettledToolbar()) return true;
|
|
1514
|
+
if (this.disposed || this.props.isActive === false || this.horizontalTouch ||
|
|
1515
|
+
this.transitionTimer !== null || this.pageScrollState !== "idle" || !this.root?.isConnected) return false;
|
|
1516
|
+
const actual = this.readTabProgress();
|
|
1517
|
+
if (actual === null || Math.abs(actual - this.state.selectedPage) > 0.001) return false;
|
|
1518
|
+
const config = this.props.nativeTabBar!;
|
|
1519
|
+
const keys: string[] = [];
|
|
1520
|
+
React.Children.forEach(this.props.children, child => {
|
|
1521
|
+
if (child !== null && child !== undefined && typeof child !== "boolean") keys.push(pageKey(child, keys.length));
|
|
1522
|
+
});
|
|
1523
|
+
const itemKeys = config.items.map(item => item.key);
|
|
1524
|
+
const valid = keys.length > 0 && new Set(keys).size === keys.length &&
|
|
1525
|
+
new Set(itemKeys).size === itemKeys.length && keys.every(key => itemKeys.includes(key));
|
|
1526
|
+
return !valid || !keys.includes(config.selectedKey ?? "") || keys[this.state.selectedPage] === config.selectedKey;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
private cancelToolbarPending() {
|
|
1530
|
+
if (this.toolbarPendingIdentity || this.toolbarImage || this.toolbarReadyIcon) this.toolbarGeneration += 1;
|
|
1531
|
+
if (this.toolbarImage) this.toolbarImage.onload = this.toolbarImage.onerror = null;
|
|
1532
|
+
this.toolbarImage = null;
|
|
1533
|
+
this.toolbarPendingIdentity = "";
|
|
1534
|
+
this.toolbarReadyIcon = null;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
private setToolbarInteractive(enabled: boolean) {
|
|
1538
|
+
const button = this.toolbarButton;
|
|
1539
|
+
if (!button) return;
|
|
1540
|
+
if (!enabled) {
|
|
1541
|
+
if (button.ownerDocument.activeElement === button) button.blur();
|
|
1542
|
+
if (this.toolbarTouchKey !== undefined) this.toolbarTouchKey = null;
|
|
1543
|
+
}
|
|
1544
|
+
button.disabled = !enabled;
|
|
1545
|
+
button.style.pointerEvents = enabled ? "auto" : "none";
|
|
1546
|
+
button.tabIndex = enabled ? 0 : -1;
|
|
1547
|
+
button.setAttribute("aria-hidden", String(!enabled));
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
private suspendToolbar() {
|
|
1551
|
+
if (!this.ownsSettledToolbar()) return;
|
|
1552
|
+
this.setToolbarInteractive(false);
|
|
1553
|
+
this.cancelToolbarPending();
|
|
1554
|
+
if (this.toolbarAnimation && this.toolbarButton) {
|
|
1555
|
+
const opacity = this.toolbarButton.ownerDocument.defaultView?.getComputedStyle(this.toolbarButton).opacity;
|
|
1556
|
+
this.toolbarAnimation.cancel();
|
|
1557
|
+
this.toolbarAnimation = null;
|
|
1558
|
+
this.toolbarButton.style.opacity = opacity || this.toolbarButton.style.opacity;
|
|
1559
|
+
this.toolbarPresenceInterrupted = true;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
private setToolbarSlot = (slot: HTMLDivElement | null) => {
|
|
1564
|
+
if (this.toolbarSlot === slot) return;
|
|
1565
|
+
this.toolbarAnimation?.cancel();
|
|
1566
|
+
this.toolbarAnimation = null;
|
|
1567
|
+
this.cancelToolbarPending();
|
|
1568
|
+
this.toolbarGeneration += 1;
|
|
1569
|
+
this.toolbarButton?.remove();
|
|
1570
|
+
this.toolbarButton = null;
|
|
1571
|
+
this.toolbarOwnerKey = undefined;
|
|
1572
|
+
this.toolbarOwnerEntry = undefined;
|
|
1573
|
+
this.toolbarIconIdentity = "";
|
|
1574
|
+
this.toolbarLoadedIcon = null;
|
|
1575
|
+
this.toolbarFailedIdentity = "";
|
|
1576
|
+
this.toolbarPresence = false;
|
|
1577
|
+
this.toolbarPresenceInterrupted = false;
|
|
1578
|
+
this.toolbarTouchKey = null;
|
|
1579
|
+
this.toolbarSlot = slot;
|
|
1580
|
+
if (slot) this.syncToolbar();
|
|
1581
|
+
};
|
|
1582
|
+
|
|
1583
|
+
private animateToolbar(visible: boolean) {
|
|
1584
|
+
const button = this.toolbarButton;
|
|
1585
|
+
if (!button || (this.toolbarPresence === visible && !this.toolbarPresenceInterrupted)) return;
|
|
1586
|
+
this.toolbarPresenceInterrupted = false;
|
|
1587
|
+
this.toolbarPresence = visible;
|
|
1588
|
+
const current = button.ownerDocument.defaultView?.getComputedStyle(button).opacity ?? button.style.opacity;
|
|
1589
|
+
this.toolbarAnimation?.cancel();
|
|
1590
|
+
this.toolbarAnimation = null;
|
|
1591
|
+
button.style.opacity = visible ? "1" : "0";
|
|
1592
|
+
const finish = () => {
|
|
1593
|
+
button.hidden = !visible;
|
|
1594
|
+
if (!visible && !this.toolbarOwnerKey && this.toolbarButton === button) {
|
|
1595
|
+
button.remove();
|
|
1596
|
+
this.toolbarButton = null;
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
if (typeof button.animate !== "function") { finish(); return; }
|
|
1600
|
+
button.hidden = false;
|
|
1601
|
+
const animation = button.animate([{ opacity: current || "0" }, { opacity: visible ? "1" : "0" }], { duration: 100, fill: "forwards" });
|
|
1602
|
+
this.toolbarAnimation = animation;
|
|
1603
|
+
animation.onfinish = () => {
|
|
1604
|
+
if (this.toolbarAnimation !== animation || this.toolbarButton !== button || this.toolbarPresence !== visible) return;
|
|
1605
|
+
animation.cancel();
|
|
1606
|
+
this.toolbarAnimation = null;
|
|
1607
|
+
finish();
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
private hideToolbar(failed: boolean) {
|
|
1612
|
+
this.setToolbarInteractive(false);
|
|
1613
|
+
this.toolbarOwnerKey = undefined;
|
|
1614
|
+
this.toolbarOwnerEntry = undefined;
|
|
1615
|
+
this.toolbarButton?.removeAttribute("data-testid");
|
|
1616
|
+
this.toolbarButton?.removeAttribute("aria-label");
|
|
1617
|
+
if (failed) this.toolbarButton?.replaceChildren();
|
|
1618
|
+
this.animateToolbar(false);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
private commitToolbar(key: string, entry: CollapsiblePagerToolbarItem, icon: SVGSVGElement, identity: string) {
|
|
1622
|
+
const button = this.toolbarButton;
|
|
1623
|
+
if (!button || !this.toolbarCanCommit()) return;
|
|
1624
|
+
if (this.toolbarOwnerKey !== key && this.toolbarTouchKey !== undefined) this.toolbarTouchKey = null;
|
|
1625
|
+
const size = Math.min(128, Math.max(1, entry.size ?? 38));
|
|
1626
|
+
const iconSize = Math.min(size, Math.max(1, entry.iconSize ?? 24));
|
|
1627
|
+
const contentWidth = Math.min(size, Math.max(0, entry.contentWidth ?? 24));
|
|
1628
|
+
const trailingInset = Math.min(128, Math.max(0, entry.trailingInset ?? 20));
|
|
1629
|
+
if (button.firstChild !== icon) button.replaceChildren(icon);
|
|
1630
|
+
Object.assign(button.style, { position: "absolute", width: `${size}px`, height: `${size}px`, borderRadius: "50%", top: "50%", transform: "translateY(-50%)",
|
|
1631
|
+
insetInlineEnd: `${trailingInset - (size - contentWidth) / 2}px`, padding: `${(size - iconSize) / 2}px`, color: entry.iconColor ?? "#000000" });
|
|
1632
|
+
button.style.setProperty("--pager-toolbar-base", entry.selected ? entry.selectedBackgroundColor ?? "transparent" : "transparent");
|
|
1633
|
+
button.style.setProperty("--pager-toolbar-hover", entry.hoverBackgroundColor ?? "transparent");
|
|
1634
|
+
button.style.setProperty("--pager-toolbar-pressed", entry.pressedBackgroundColor ?? "transparent");
|
|
1635
|
+
button.setAttribute("aria-label", entry.accessibilityLabel ?? "");
|
|
1636
|
+
if (entry.testID) button.setAttribute("data-testid", entry.testID); else button.removeAttribute("data-testid");
|
|
1637
|
+
this.toolbarOwnerKey = key;
|
|
1638
|
+
this.toolbarOwnerEntry = { ...entry };
|
|
1639
|
+
this.toolbarIconIdentity = identity;
|
|
1640
|
+
this.toolbarLoadedIcon = icon;
|
|
1641
|
+
this.toolbarPendingIdentity = "";
|
|
1642
|
+
this.toolbarReadyIcon = null;
|
|
1643
|
+
this.toolbarImage = null;
|
|
1644
|
+
this.animateToolbar(true);
|
|
1645
|
+
this.setToolbarInteractive(true);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
private syncToolbar() {
|
|
1649
|
+
const slot = this.toolbarSlot;
|
|
1650
|
+
if (!slot) return;
|
|
1651
|
+
if (!this.toolbarCanCommit()) { this.suspendToolbar(); return; }
|
|
1652
|
+
const config = this.props.nativeTabBar;
|
|
1653
|
+
const key = config?.controlled ? config.selectedKey : config?.items[this.state.selectedPage]?.key;
|
|
1654
|
+
const entry = key ? config?.toolbar?.[key] : undefined;
|
|
1655
|
+
if (!entry?.iconName || !key) {
|
|
1656
|
+
this.cancelToolbarPending();
|
|
1657
|
+
this.hideToolbar(false);
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
let button = this.toolbarButton;
|
|
1661
|
+
if (!button) {
|
|
1662
|
+
button = slot.ownerDocument.createElement("button");
|
|
1663
|
+
button.type = "button";
|
|
1664
|
+
button.className = "ok-pager-toolbar";
|
|
1665
|
+
button.style.opacity = "0";
|
|
1666
|
+
button.hidden = true;
|
|
1667
|
+
button.disabled = true;
|
|
1668
|
+
button.addEventListener("pointerdown", () => { this.toolbarTouchKey = button!.disabled ? null : this.toolbarOwnerKey ?? null; });
|
|
1669
|
+
button.addEventListener("pointercancel", () => { this.toolbarTouchKey = null; });
|
|
1670
|
+
button.onclick = event => {
|
|
1671
|
+
if (this.toolbarButton !== event.currentTarget) return;
|
|
1672
|
+
const pointer = event.detail !== 0;
|
|
1673
|
+
const touched = this.toolbarTouchKey;
|
|
1674
|
+
if (pointer) this.toolbarTouchKey = undefined;
|
|
1675
|
+
const current = this.props.nativeTabBar;
|
|
1676
|
+
const semantic = current?.controlled ? current.selectedKey : current?.items[this.state.selectedPage]?.key;
|
|
1677
|
+
const owner = this.toolbarOwnerKey;
|
|
1678
|
+
if (button!.disabled || !this.toolbarCanCommit() || !owner || owner !== semantic ||
|
|
1679
|
+
!this.toolbarOwnerEntry || (pointer && touched !== owner)) return;
|
|
1680
|
+
const rect = button!.getBoundingClientRect();
|
|
1681
|
+
this.props.onNativeToolbarPress?.({ nativeEvent: { key: owner,
|
|
1682
|
+
anchorRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } } } as ReactNative.NativeSyntheticEvent<CollapsiblePagerToolbarPress>);
|
|
1683
|
+
};
|
|
1684
|
+
slot.appendChild(button);
|
|
1685
|
+
this.toolbarButton = button;
|
|
1686
|
+
this.toolbarPresence = false;
|
|
1687
|
+
}
|
|
1688
|
+
const size = Math.min(128, Math.max(1, entry.size ?? 38));
|
|
1689
|
+
const iconSize = Math.min(size, Math.max(1, entry.iconSize ?? 24));
|
|
1690
|
+
const identity = `${entry.iconName}|${entry.iconColor ?? "#000000"}|${iconSize}`;
|
|
1691
|
+
if (identity === this.toolbarIconIdentity && this.toolbarLoadedIcon) {
|
|
1692
|
+
this.cancelToolbarPending();
|
|
1693
|
+
this.commitToolbar(key, entry, this.toolbarLoadedIcon, identity);
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
if (identity === this.toolbarPendingIdentity) {
|
|
1697
|
+
if (this.toolbarReadyIcon) this.commitToolbar(key, entry, this.toolbarReadyIcon, identity);
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
this.cancelToolbarPending();
|
|
1701
|
+
this.setToolbarInteractive(false);
|
|
1702
|
+
this.toolbarPendingIdentity = identity;
|
|
1703
|
+
if (identity === this.toolbarFailedIdentity) { this.hideToolbar(true); return; }
|
|
1704
|
+
const generation = ++this.toolbarGeneration;
|
|
1705
|
+
const icon = createNamedIcon(button.ownerDocument, entry.iconName);
|
|
1706
|
+
icon.setAttribute("width", String(iconSize)); icon.setAttribute("height", String(iconSize));
|
|
1707
|
+
const use = icon.querySelector("use");
|
|
1708
|
+
const fail = () => {
|
|
1709
|
+
if (this.toolbarGeneration !== generation || this.toolbarPendingIdentity !== identity) return;
|
|
1710
|
+
this.toolbarImage = null;
|
|
1711
|
+
this.toolbarFailedIdentity = identity;
|
|
1712
|
+
this.hideToolbar(true);
|
|
1713
|
+
};
|
|
1714
|
+
if (!use) { fail(); return; }
|
|
1715
|
+
const ready = () => {
|
|
1716
|
+
if (this.disposed || this.toolbarGeneration !== generation || this.toolbarPendingIdentity !== identity) return;
|
|
1717
|
+
this.toolbarImage = null;
|
|
1718
|
+
this.toolbarReadyIcon = icon;
|
|
1719
|
+
this.syncToolbar();
|
|
1720
|
+
};
|
|
1721
|
+
const href = use.getAttribute("href") ?? use.getAttribute("xlink:href") ?? "";
|
|
1722
|
+
const view = button.ownerDocument.defaultView;
|
|
1723
|
+
if (view?.Image && href.split("#")[0]) {
|
|
1724
|
+
const image = new view.Image();
|
|
1725
|
+
this.toolbarImage = image;
|
|
1726
|
+
image.onload = ready;
|
|
1727
|
+
image.onerror = fail;
|
|
1728
|
+
image.src = href.split("#")[0];
|
|
1729
|
+
} else ready();
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
private renderNativeTabBar() {
|
|
1733
|
+
const config = this.props.nativeTabBar;
|
|
1734
|
+
if (!config?.items.length || (config.style?.variant !== "text" && config.controlled !== true && config.toolbar === undefined)) return null;
|
|
1735
|
+
const style = config.style;
|
|
1736
|
+
const variant = style?.variant ?? "underline";
|
|
1737
|
+
const selectedKey = config.controlled ? config.selectedKey : config.items[this.state.selectedPage]?.key;
|
|
1738
|
+
const toolbarEntries = config.toolbar === undefined ? undefined : Object.values(config.toolbar);
|
|
1739
|
+
const reservedWidth = toolbarEntries === undefined ? 0 : toolbarEntries.length === 0 ? 44 : Math.max(...toolbarEntries.map(entry => {
|
|
1740
|
+
const size = Math.min(128, Math.max(1, entry.size ?? 38));
|
|
1741
|
+
return Math.min(size, Math.max(0, entry.contentWidth ?? 24)) + Math.min(128, Math.max(0, entry.trailingInset ?? 20));
|
|
1742
|
+
}));
|
|
1743
|
+
const segmented = variant === "segmented";
|
|
1744
|
+
const reserveTextFaces = config.controlled && variant === "text";
|
|
1745
|
+
const colorWeights = this.tabColorWeights();
|
|
1746
|
+
const fontOwnerKey = this.tabFontOwnerKey(colorWeights);
|
|
1747
|
+
return React.createElement("div", {
|
|
1748
|
+
className: "ok-pager-tab-bar",
|
|
1749
|
+
dir: this.props.layoutDirection === "rtl" || ((this.props.layoutDirection ?? "locale") === "locale" && I18nManager.isRTL) ? "rtl" : "ltr",
|
|
1750
|
+
style: { display: "flex", alignItems: "center", position: "relative", height: style?.height ?? 44,
|
|
1751
|
+
backgroundColor: String(style?.backgroundColor ?? "transparent"), minWidth: 0 },
|
|
1752
|
+
},
|
|
1753
|
+
React.createElement("style", null, `.ok-pager-tab{box-sizing:border-box;appearance:none;border:0;background:transparent;cursor:default;white-space:nowrap;flex-shrink:0;line-height:normal}.ok-pager-toolbar{box-sizing:border-box;appearance:none;border:1px solid transparent;cursor:default;display:flex;align-items:center;justify-content:center;background:var(--pager-toolbar-base)}.ok-pager-toolbar:hover:enabled{background:var(--pager-toolbar-hover)}.ok-pager-toolbar:active:enabled{background:var(--pager-toolbar-pressed)}`),
|
|
1754
|
+
React.createElement("div", { role: "tablist", style: { display: "flex", overflowX: segmented ? "hidden" : "auto", flex: 1,
|
|
1755
|
+
padding: `${style?.contentPaddingVertical ?? 0}px ${style?.contentPaddingHorizontal ?? 20}px`, gap: style?.itemSpacing ?? 8 } },
|
|
1756
|
+
...config.items.map((item, position) => {
|
|
1757
|
+
const selected = item.key === selectedKey;
|
|
1758
|
+
const fontSelected = item.key === fontOwnerKey;
|
|
1759
|
+
return React.createElement("button", {
|
|
1760
|
+
key: item.key, role: "tab", type: "button", className: "ok-pager-tab", "aria-selected": selected,
|
|
1761
|
+
ref: (button: HTMLButtonElement | null) => { if (button) this.tabButtons.set(item.key, button); else this.tabButtons.delete(item.key); },
|
|
1762
|
+
"aria-label": item.accessibilityLabel ?? item.title, "data-testid": item.testID,
|
|
1763
|
+
style: { padding: variant === "text" ? "6px 10px" : "6px 8px", minWidth: 44, height: (style?.height ?? 44) - 2 * (style?.contentPaddingVertical ?? 0),
|
|
1764
|
+
fontSize: style?.fontSize ?? (variant === "text" ? 18 : 16),
|
|
1765
|
+
fontWeight: variant === "text" && fontSelected ? 600 : 500,
|
|
1766
|
+
fontFamily: reserveTextFaces ? style?.fontFamily : fontSelected ? style?.activeFontFamily ?? style?.fontFamily : style?.fontFamily,
|
|
1767
|
+
display: reserveTextFaces ? "inline-grid" : undefined,
|
|
1768
|
+
gridTemplateAreas: reserveTextFaces ? '"label"' : undefined,
|
|
1769
|
+
alignItems: reserveTextFaces ? "center" : undefined,
|
|
1770
|
+
color: this.tabColor(selected, colorWeights ? colorWeights.get(item.key) ?? 0 : undefined),
|
|
1771
|
+
flex: segmented ? 1 : undefined, borderRadius: segmented ? 999 : 0,
|
|
1772
|
+
backgroundColor: segmented && selected ? String(style?.indicatorColor ?? "transparent") : "transparent",
|
|
1773
|
+
borderBottom: variant === "underline" && selected ? `${style?.indicatorHeight ?? 2}px solid ${String(style?.indicatorColor ?? "#000000")}` : undefined },
|
|
1774
|
+
onClick: () => {
|
|
1775
|
+
if (!config.controlled) {
|
|
1776
|
+
const animated = this.props.nativeTabPressAnimationEnabled ?? Math.abs(position - this.state.selectedPage) <= 1;
|
|
1777
|
+
if (animated) this.setPage(position); else this.setPageWithoutAnimation(position);
|
|
1778
|
+
}
|
|
1779
|
+
this.props.onNativeTabPress?.({ nativeEvent: { position, key: item.key } } as CollapsiblePagerViewOnNativeTabPressEvent);
|
|
1780
|
+
},
|
|
1781
|
+
}, reserveTextFaces ? [
|
|
1782
|
+
React.createElement("span", { key: "label", className: "ok-pager-tab-label", style: {
|
|
1783
|
+
gridArea: "label", fontFamily: fontSelected ? style?.activeFontFamily ?? style?.fontFamily : style?.fontFamily,
|
|
1784
|
+
} }, item.title),
|
|
1785
|
+
...[false, true].map(active => React.createElement("span", {
|
|
1786
|
+
key: active ? "active-width" : "normal-width", "aria-hidden": true,
|
|
1787
|
+
style: { gridArea: "label", visibility: "hidden", pointerEvents: "none", userSelect: "none",
|
|
1788
|
+
fontWeight: active ? 600 : 500,
|
|
1789
|
+
fontFamily: active ? style?.activeFontFamily ?? style?.fontFamily : style?.fontFamily },
|
|
1790
|
+
}, item.title)),
|
|
1791
|
+
] : item.title);
|
|
1792
|
+
})),
|
|
1793
|
+
config.toolbar !== undefined ? React.createElement("div", { ref: this.setToolbarSlot, className: "ok-pager-toolbar-slot", style: { flexShrink: 0, width: reservedWidth, height: "100%", position: "relative" } }) : null);
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1341
1796
|
render() {
|
|
1342
1797
|
const {
|
|
1343
1798
|
children: _children,
|
|
1799
|
+
nativeTabBar: _nativeTabBar,
|
|
1800
|
+
nativeTabPressAnimationEnabled: _nativeTabPressAnimationEnabled,
|
|
1801
|
+
onNativeTabPress: _onNativeTabPress,
|
|
1802
|
+
onNativeToolbarPress: _onNativeToolbarPress,
|
|
1344
1803
|
header,
|
|
1345
1804
|
stickyHeader,
|
|
1346
1805
|
topOverlay: _topOverlay,
|
|
@@ -1436,8 +1895,8 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
1436
1895
|
collapseAnimation,
|
|
1437
1896
|
]}
|
|
1438
1897
|
>
|
|
1439
|
-
{this.hasExplicitStickyHeaderHeight ? stickyHeader : (
|
|
1440
|
-
<View ref={this.setStickyContent}>{stickyHeader}</View>
|
|
1898
|
+
{this.hasExplicitStickyHeaderHeight ? <>{this.renderNativeTabBar()}{stickyHeader}</> : (
|
|
1899
|
+
<View ref={this.setStickyContent}>{this.renderNativeTabBar()}{stickyHeader}</View>
|
|
1441
1900
|
)}
|
|
1442
1901
|
</View>
|
|
1443
1902
|
<View
|
|
@@ -38,6 +38,10 @@ export type OnNativeTabPressEventData = Readonly<{
|
|
|
38
38
|
position: CodegenTypes.Int32;
|
|
39
39
|
key: string;
|
|
40
40
|
}>;
|
|
41
|
+
export type OnNativeToolbarPressEventData = Readonly<{
|
|
42
|
+
key: string;
|
|
43
|
+
anchorRect: Readonly<{ x: CodegenTypes.Double; y: CodegenTypes.Double; width: CodegenTypes.Double; height: CodegenTypes.Double }>;
|
|
44
|
+
}>;
|
|
41
45
|
export type OnScrollEdgeCapabilityEventData = Readonly<{ available: boolean }>;
|
|
42
46
|
|
|
43
47
|
/**
|
|
@@ -60,6 +64,7 @@ export interface NativeProps extends ViewProps {
|
|
|
60
64
|
externalTopOverlayTag?: CodegenTypes.WithDefault<CodegenTypes.Int32, 0>;
|
|
61
65
|
pageKeys?: string;
|
|
62
66
|
retainedPages?: string;
|
|
67
|
+
nativeTabBarConfig?: string;
|
|
63
68
|
nativeTabBarItems?: string;
|
|
64
69
|
nativeTabBarHeight?: CodegenTypes.Double;
|
|
65
70
|
nativeTabBarVariant?: string;
|
|
@@ -81,6 +86,7 @@ export interface NativeProps extends ViewProps {
|
|
|
81
86
|
onPageSelected?: CodegenTypes.DirectEventHandler<OnPageSelectedEventData>;
|
|
82
87
|
onPageScrollStateChanged?: CodegenTypes.DirectEventHandler<OnPageScrollStateChangedEventData>;
|
|
83
88
|
onCollapsibleStateChanged?: CodegenTypes.DirectEventHandler<OnCollapsibleStateChangedEventData>;
|
|
89
|
+
onNativeToolbarPress?: CodegenTypes.DirectEventHandler<OnNativeToolbarPressEventData>;
|
|
84
90
|
onNativeTabPress?: CodegenTypes.DirectEventHandler<OnNativeTabPressEventData>;
|
|
85
91
|
onNativeSubHeaderPress?: CodegenTypes.DirectEventHandler<OnNativeTabPressEventData>;
|
|
86
92
|
onScrollEdgeCapability?: CodegenTypes.DirectEventHandler<OnScrollEdgeCapabilityEventData>;
|
package/src/NativeScroller.tsx
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
TextInput,
|
|
8
8
|
View,
|
|
9
9
|
type GestureResponderEvent,
|
|
10
|
-
type HostInstance,
|
|
11
10
|
type RefreshControlProps,
|
|
12
11
|
type ScrollView,
|
|
13
12
|
type ScrollViewProps,
|
|
@@ -62,7 +61,7 @@ type HostRef = React.ElementRef<typeof NativeScrollerHost>;
|
|
|
62
61
|
|
|
63
62
|
export interface NativeScrollerRef
|
|
64
63
|
extends Pick<
|
|
65
|
-
|
|
64
|
+
HostRef,
|
|
66
65
|
| "measure"
|
|
67
66
|
| "measureInWindow"
|
|
68
67
|
| "measureLayout"
|
|
@@ -166,7 +165,7 @@ export const NativeScroller = React.forwardRef<
|
|
|
166
165
|
|
|
167
166
|
React.useImperativeHandle(
|
|
168
167
|
forwardedRef,
|
|
169
|
-
() => ({
|
|
168
|
+
(): NativeScrollerRef => ({
|
|
170
169
|
scrollTo(options, x, animated) {
|
|
171
170
|
const host = hostRef.current;
|
|
172
171
|
if (!host) return;
|