@player-ui/auto-scroll-manager-plugin-react 0.8.0--canary.307.9645 → 0.8.0-next.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/dist/cjs/index.cjs +201 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/{index.esm.js → index.legacy-esm.js} +58 -43
- package/dist/index.mjs +160 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -58
- package/src/__tests__/plugin.test.tsx +411 -0
- package/src/hooks.tsx +5 -5
- package/src/index.tsx +2 -2
- package/src/plugin.tsx +18 -15
- package/src/scrollIntoViewWithOffset.ts +3 -3
- package/types/hooks.d.ts +27 -0
- package/types/index.d.ts +3 -0
- package/types/plugin.d.ts +42 -0
- package/types/scrollIntoViewWithOffset.d.ts +9 -0
- package/dist/index.cjs.js +0 -156
- package/dist/index.d.ts +0 -69
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/index.tsx
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
AutoScrollManagerContext: () => AutoScrollManagerContext,
|
|
34
|
+
AutoScrollManagerPlugin: () => AutoScrollManagerPlugin,
|
|
35
|
+
AutoScrollProvider: () => AutoScrollProvider,
|
|
36
|
+
ScrollType: () => ScrollType,
|
|
37
|
+
useRegisterAsScrollable: () => useRegisterAsScrollable
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(src_exports);
|
|
40
|
+
|
|
41
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
42
|
+
var import_react = __toESM(require("react"));
|
|
43
|
+
|
|
44
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/scrollIntoViewWithOffset.ts
|
|
45
|
+
var import_seamless_scroll_polyfill = require("seamless-scroll-polyfill");
|
|
46
|
+
var scrollIntoViewWithOffset_default = (node, baseElement, offset) => {
|
|
47
|
+
(0, import_seamless_scroll_polyfill.scrollTo)(window, {
|
|
48
|
+
behavior: "smooth",
|
|
49
|
+
top: node.getBoundingClientRect().top - baseElement.getBoundingClientRect().top - offset
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
54
|
+
var AutoScrollManagerContext = import_react.default.createContext({ register: () => {
|
|
55
|
+
} });
|
|
56
|
+
var useRegisterAsScrollable = () => {
|
|
57
|
+
const { register } = import_react.default.useContext(AutoScrollManagerContext);
|
|
58
|
+
return register;
|
|
59
|
+
};
|
|
60
|
+
var AutoScrollProvider = ({
|
|
61
|
+
getElementToScrollTo,
|
|
62
|
+
getBaseElement,
|
|
63
|
+
offset,
|
|
64
|
+
children
|
|
65
|
+
}) => {
|
|
66
|
+
const [scrollableMap, setScrollableMap] = (0, import_react.useState)(/* @__PURE__ */ new Map());
|
|
67
|
+
const updateScrollableMap = (key, value) => {
|
|
68
|
+
setScrollableMap((prev) => {
|
|
69
|
+
const nm = new Map(prev);
|
|
70
|
+
if (!nm.get(key)) {
|
|
71
|
+
nm.set(key, /* @__PURE__ */ new Set());
|
|
72
|
+
}
|
|
73
|
+
nm.get(key)?.add(value);
|
|
74
|
+
return nm;
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const register = (data) => {
|
|
78
|
+
updateScrollableMap(data.type, data.ref);
|
|
79
|
+
};
|
|
80
|
+
(0, import_react.useEffect)(() => {
|
|
81
|
+
const node = document.getElementById(getElementToScrollTo(scrollableMap));
|
|
82
|
+
if (node) {
|
|
83
|
+
scrollIntoViewWithOffset_default(node, getBaseElement() || document.body, offset);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return /* @__PURE__ */ import_react.default.createElement(AutoScrollManagerContext.Provider, { value: { register } }, children);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/plugin.tsx
|
|
90
|
+
var import_react2 = __toESM(require("react"));
|
|
91
|
+
var ScrollType = /* @__PURE__ */ ((ScrollType2) => {
|
|
92
|
+
ScrollType2[ScrollType2["ValidationError"] = 0] = "ValidationError";
|
|
93
|
+
ScrollType2[ScrollType2["FirstAppearance"] = 1] = "FirstAppearance";
|
|
94
|
+
ScrollType2[ScrollType2["Unknown"] = 2] = "Unknown";
|
|
95
|
+
return ScrollType2;
|
|
96
|
+
})(ScrollType || {});
|
|
97
|
+
var AutoScrollManagerPlugin = class {
|
|
98
|
+
constructor(config) {
|
|
99
|
+
this.name = "auto-scroll-manager";
|
|
100
|
+
this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;
|
|
101
|
+
this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;
|
|
102
|
+
this.getBaseElement = config.getBaseElement ?? (() => null);
|
|
103
|
+
this.offset = config.offset ?? 0;
|
|
104
|
+
this.initialRender = false;
|
|
105
|
+
this.failedNavigation = false;
|
|
106
|
+
this.alreadyScrolledTo = [];
|
|
107
|
+
this.scrollFn = this.calculateScroll.bind(this);
|
|
108
|
+
}
|
|
109
|
+
getFirstScrollableElement(idList, type) {
|
|
110
|
+
const highestElement = {
|
|
111
|
+
id: "",
|
|
112
|
+
ypos: 0
|
|
113
|
+
};
|
|
114
|
+
const ypos = window.scrollY;
|
|
115
|
+
idList.forEach((id) => {
|
|
116
|
+
const element = document.getElementById(id);
|
|
117
|
+
if (type === 0 /* ValidationError */ && element?.getAttribute("aria-invalid") === "false") {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (type === 1 /* FirstAppearance */) {
|
|
121
|
+
if (this.alreadyScrolledTo.indexOf(id) !== -1) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.alreadyScrolledTo.push(id);
|
|
125
|
+
}
|
|
126
|
+
const epos = element?.getBoundingClientRect().top;
|
|
127
|
+
if (epos !== void 0 && (epos + ypos < highestElement.ypos || highestElement.id === "")) {
|
|
128
|
+
highestElement.id = id;
|
|
129
|
+
highestElement.ypos = ypos + epos;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return highestElement.id;
|
|
133
|
+
}
|
|
134
|
+
calculateScroll(scrollableElements) {
|
|
135
|
+
let currentScroll = 1 /* FirstAppearance */;
|
|
136
|
+
if (this.initialRender) {
|
|
137
|
+
if (this.autoScrollOnLoad) {
|
|
138
|
+
currentScroll = 0 /* ValidationError */;
|
|
139
|
+
}
|
|
140
|
+
this.initialRender = false;
|
|
141
|
+
} else if (this.failedNavigation) {
|
|
142
|
+
if (this.autoFocusOnErrorField) {
|
|
143
|
+
currentScroll = 0 /* ValidationError */;
|
|
144
|
+
}
|
|
145
|
+
this.failedNavigation = false;
|
|
146
|
+
}
|
|
147
|
+
const elementList = scrollableElements.get(currentScroll);
|
|
148
|
+
if (elementList) {
|
|
149
|
+
const element = this.getFirstScrollableElement(
|
|
150
|
+
elementList,
|
|
151
|
+
currentScroll
|
|
152
|
+
);
|
|
153
|
+
return element ?? "";
|
|
154
|
+
}
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
157
|
+
// Hooks into player flow to determine what scroll targets need to be evaluated at specific lifecycle points
|
|
158
|
+
apply(player) {
|
|
159
|
+
player.hooks.flowController.tap(this.name, (fc) => {
|
|
160
|
+
fc.hooks.flow.tap(this.name, (flow) => {
|
|
161
|
+
flow.hooks.transition.tap(this.name, () => {
|
|
162
|
+
this.initialRender = true;
|
|
163
|
+
this.failedNavigation = false;
|
|
164
|
+
this.alreadyScrolledTo = [];
|
|
165
|
+
window.scroll(0, 0);
|
|
166
|
+
});
|
|
167
|
+
flow.hooks.skipTransition.intercept({
|
|
168
|
+
call: () => {
|
|
169
|
+
this.failedNavigation = true;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
applyReact(reactPlayer) {
|
|
176
|
+
reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
|
|
177
|
+
const { scrollFn, getBaseElement, offset } = this;
|
|
178
|
+
function AutoScrollManagerComponent() {
|
|
179
|
+
return /* @__PURE__ */ import_react2.default.createElement(
|
|
180
|
+
AutoScrollProvider,
|
|
181
|
+
{
|
|
182
|
+
getElementToScrollTo: scrollFn,
|
|
183
|
+
getBaseElement,
|
|
184
|
+
offset
|
|
185
|
+
},
|
|
186
|
+
/* @__PURE__ */ import_react2.default.createElement(Comp, null)
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return AutoScrollManagerComponent;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
194
|
+
0 && (module.exports = {
|
|
195
|
+
AutoScrollManagerContext,
|
|
196
|
+
AutoScrollManagerPlugin,
|
|
197
|
+
AutoScrollProvider,
|
|
198
|
+
ScrollType,
|
|
199
|
+
useRegisterAsScrollable
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/index.tsx","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/scrollIntoViewWithOffset.ts","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/plugin.tsx"],"sourcesContent":["export * from \"./hooks\";\nexport * from \"./plugin\";\n","import type { PropsWithChildren } from \"react\";\nimport React, { useEffect, useState } from \"react\";\nimport scrollIntoViewWithOffset from \"./scrollIntoViewWithOffset\";\nimport type { ScrollType } from \"./index\";\n\nexport interface AutoScrollProviderProps {\n /** Return the element to scroll to based on the registered types */\n getElementToScrollTo: (\n scrollableElements: Map<ScrollType, Set<string>>,\n ) => string;\n /** Optional function to get container element, which is used for calculating offset (default: document.body) */\n getBaseElement: () => HTMLElement | undefined | null;\n /** Additional offset to be used (default: 0) */\n offset: number;\n}\n\nexport interface RegisterData {\n /** when to scroll to the target */\n type: ScrollType;\n\n /** the html id to scroll to */\n ref: string;\n}\n\nexport type ScrollFunction = (registerData: RegisterData) => void;\n\nexport const AutoScrollManagerContext = React.createContext<{\n /** function to register a scroll target */\n register: ScrollFunction;\n}>({ register: () => {} });\n\n/** hook to register as a scroll target */\nexport const useRegisterAsScrollable = (): ScrollFunction => {\n const { register } = React.useContext(AutoScrollManagerContext);\n\n return register;\n};\n\n/** Component to handle scrolling */\nexport const AutoScrollProvider = ({\n getElementToScrollTo,\n getBaseElement,\n offset,\n children,\n}: PropsWithChildren<AutoScrollProviderProps>) => {\n // Tracker for what elements are registered to be scroll targets\n // Key is the type (initial, validation, appear)\n // Value is a set of target ids\n const [scrollableMap, setScrollableMap] = useState<\n Map<ScrollType, Set<string>>\n >(new Map());\n\n /** Add a new entry as a scroll target */\n const updateScrollableMap = (key: ScrollType, value: string) => {\n setScrollableMap((prev) => {\n const nm = new Map(prev);\n\n if (!nm.get(key)) {\n nm.set(key, new Set());\n }\n\n nm.get(key)?.add(value);\n\n return nm;\n });\n };\n\n /** register a new scroll target */\n const register: ScrollFunction = (data) => {\n updateScrollableMap(data.type, data.ref);\n };\n\n useEffect(() => {\n const node = document.getElementById(getElementToScrollTo(scrollableMap));\n\n if (node) {\n scrollIntoViewWithOffset(node, getBaseElement() || document.body, offset);\n }\n });\n\n return (\n <AutoScrollManagerContext.Provider value={{ register }}>\n {children}\n </AutoScrollManagerContext.Provider>\n );\n};\n","/**\n * Scroll to the given element\n-* @param node Element to scroll to\n-* @param baseElement Container element used to calculate offset\n-* @param offset Additional offset\n */\n\nimport { scrollTo } from \"seamless-scroll-polyfill\";\n\nexport default (\n node: HTMLElement,\n baseElement: HTMLElement,\n offset: number,\n) => {\n scrollTo(window, {\n behavior: \"smooth\",\n top:\n node.getBoundingClientRect().top -\n baseElement.getBoundingClientRect().top -\n offset,\n });\n};\n","import type { ReactPlayer, ReactPlayerPlugin } from \"@player-ui/react\";\nimport type { Player } from \"@player-ui/react\";\nimport React from \"react\";\nimport { AutoScrollProvider } from \"./hooks\";\n\nexport enum ScrollType {\n ValidationError,\n FirstAppearance,\n Unknown,\n}\n\nexport interface AutoScrollManagerConfig {\n /** Config to auto-scroll on load */\n autoScrollOnLoad?: boolean;\n /** Config to auto-focus on an error */\n autoFocusOnErrorField?: boolean;\n /** Optional function to get container element, which is used for calculating offset (default: document.body) */\n getBaseElement?: () => HTMLElement | undefined | null;\n /** Additional offset to be used (default: 0) */\n offset?: number;\n}\n\n/** A plugin to manage scrolling behavior */\nexport class AutoScrollManagerPlugin implements ReactPlayerPlugin {\n name = \"auto-scroll-manager\";\n\n /** Toggles if we should auto scroll to to the first failed validation on page load */\n private autoScrollOnLoad: boolean;\n\n /** Toggles if we should auto scroll to the first failed validation on navigation failure */\n private autoFocusOnErrorField: boolean;\n\n /** tracks if its the initial page render */\n private initialRender: boolean;\n\n /** tracks if the navigation failed */\n private failedNavigation: boolean;\n\n /** function to return the base of the scrollable area */\n private getBaseElement: () => HTMLElement | undefined | null;\n\n /** static offset */\n private offset: number;\n\n /** map of scroll type to set of ids that are registered under that type */\n private alreadyScrolledTo: Array<string>;\n private scrollFn: (\n scrollableElements: Map<ScrollType, Set<string>>,\n ) => string;\n\n constructor(config: AutoScrollManagerConfig) {\n this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;\n this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;\n this.getBaseElement = config.getBaseElement ?? (() => null);\n this.offset = config.offset ?? 0;\n this.initialRender = false;\n this.failedNavigation = false;\n this.alreadyScrolledTo = [];\n this.scrollFn = this.calculateScroll.bind(this);\n }\n\n getFirstScrollableElement(idList: Set<string>, type: ScrollType) {\n const highestElement = {\n id: \"\",\n ypos: 0,\n };\n const ypos = window.scrollY;\n idList.forEach((id) => {\n const element = document.getElementById(id);\n\n // if we are looking at validation errors, make sure the element is invalid\n if (\n type === ScrollType.ValidationError &&\n element?.getAttribute(\"aria-invalid\") === \"false\"\n ) {\n return;\n }\n\n // if we are just looking at elements that just appeared, make sure we haven't\n // scrolled to them before\n if (type === ScrollType.FirstAppearance) {\n if (this.alreadyScrolledTo.indexOf(id) !== -1) {\n return;\n }\n\n this.alreadyScrolledTo.push(id);\n }\n\n const epos = element?.getBoundingClientRect().top;\n if (\n epos !== undefined &&\n (epos + ypos < highestElement.ypos || highestElement.id === \"\")\n ) {\n highestElement.id = id;\n highestElement.ypos = ypos + epos;\n }\n });\n return highestElement.id;\n }\n\n calculateScroll(scrollableElements: Map<ScrollType, Set<string>>) {\n let currentScroll = ScrollType.FirstAppearance;\n if (this.initialRender) {\n if (this.autoScrollOnLoad) {\n currentScroll = ScrollType.ValidationError;\n }\n\n this.initialRender = false;\n } else if (this.failedNavigation) {\n if (this.autoFocusOnErrorField) {\n currentScroll = ScrollType.ValidationError;\n }\n\n this.failedNavigation = false;\n }\n\n const elementList = scrollableElements.get(currentScroll);\n if (elementList) {\n const element = this.getFirstScrollableElement(\n elementList,\n currentScroll,\n );\n return element ?? \"\";\n }\n\n return \"\";\n }\n\n // Hooks into player flow to determine what scroll targets need to be evaluated at specific lifecycle points\n apply(player: Player) {\n player.hooks.flowController.tap(this.name, (fc) => {\n fc.hooks.flow.tap(this.name, (flow) => {\n flow.hooks.transition.tap(this.name, () => {\n // Reset Everything\n this.initialRender = true;\n this.failedNavigation = false;\n this.alreadyScrolledTo = [];\n // Reset scroll position for new view\n window.scroll(0, 0);\n });\n flow.hooks.skipTransition.intercept({\n call: () => {\n this.failedNavigation = true;\n },\n });\n });\n });\n }\n\n applyReact(reactPlayer: ReactPlayer) {\n reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {\n const { scrollFn, getBaseElement, offset } = this;\n\n function AutoScrollManagerComponent() {\n return (\n <AutoScrollProvider\n getElementToScrollTo={scrollFn}\n getBaseElement={getBaseElement}\n offset={offset}\n >\n <Comp />\n </AutoScrollProvider>\n );\n }\n\n return AutoScrollManagerComponent;\n });\n }\n}\n"],"mappings":"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","names":["React","import_react","ScrollType","React"]}
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/scrollIntoViewWithOffset.ts
|
|
5
|
+
import { scrollTo } from "seamless-scroll-polyfill";
|
|
6
|
+
var scrollIntoViewWithOffset_default = (node, baseElement, offset) => {
|
|
5
7
|
scrollTo(window, {
|
|
6
8
|
behavior: "smooth",
|
|
7
9
|
top: node.getBoundingClientRect().top - baseElement.getBoundingClientRect().top - offset
|
|
8
10
|
});
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
14
|
+
var AutoScrollManagerContext = React.createContext({ register: () => {
|
|
12
15
|
} });
|
|
13
|
-
|
|
16
|
+
var useRegisterAsScrollable = () => {
|
|
14
17
|
const { register } = React.useContext(AutoScrollManagerContext);
|
|
15
18
|
return register;
|
|
16
19
|
};
|
|
17
|
-
|
|
20
|
+
var AutoScrollProvider = ({
|
|
18
21
|
getElementToScrollTo,
|
|
19
22
|
getBaseElement,
|
|
20
23
|
offset,
|
|
21
24
|
children
|
|
22
25
|
}) => {
|
|
23
|
-
const [scrollableMap, setScrollableMap] = useState(new Map());
|
|
26
|
+
const [scrollableMap, setScrollableMap] = useState(/* @__PURE__ */ new Map());
|
|
24
27
|
const updateScrollableMap = (key, value) => {
|
|
25
28
|
setScrollableMap((prev) => {
|
|
26
|
-
var _a;
|
|
27
29
|
const nm = new Map(prev);
|
|
28
30
|
if (!nm.get(key)) {
|
|
29
|
-
nm.set(key, new Set());
|
|
31
|
+
nm.set(key, /* @__PURE__ */ new Set());
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
nm.get(key)?.add(value);
|
|
32
34
|
return nm;
|
|
33
35
|
});
|
|
34
36
|
};
|
|
@@ -38,28 +40,27 @@ const AutoScrollProvider = ({
|
|
|
38
40
|
useEffect(() => {
|
|
39
41
|
const node = document.getElementById(getElementToScrollTo(scrollableMap));
|
|
40
42
|
if (node) {
|
|
41
|
-
|
|
43
|
+
scrollIntoViewWithOffset_default(node, getBaseElement() || document.body, offset);
|
|
42
44
|
}
|
|
43
45
|
});
|
|
44
|
-
return /* @__PURE__ */ React.createElement(AutoScrollManagerContext.Provider, {
|
|
45
|
-
value: { register }
|
|
46
|
-
}, children);
|
|
46
|
+
return /* @__PURE__ */ React.createElement(AutoScrollManagerContext.Provider, { value: { register } }, children);
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/plugin.tsx
|
|
50
|
+
import React2 from "react";
|
|
51
|
+
var ScrollType = /* @__PURE__ */ ((ScrollType2) => {
|
|
51
52
|
ScrollType2[ScrollType2["ValidationError"] = 0] = "ValidationError";
|
|
52
53
|
ScrollType2[ScrollType2["FirstAppearance"] = 1] = "FirstAppearance";
|
|
53
54
|
ScrollType2[ScrollType2["Unknown"] = 2] = "Unknown";
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
return ScrollType2;
|
|
56
|
+
})(ScrollType || {});
|
|
57
|
+
var AutoScrollManagerPlugin = class {
|
|
56
58
|
constructor(config) {
|
|
57
59
|
this.name = "auto-scroll-manager";
|
|
58
|
-
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.offset = (_d = config.offset) != null ? _d : 0;
|
|
60
|
+
this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;
|
|
61
|
+
this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;
|
|
62
|
+
this.getBaseElement = config.getBaseElement ?? (() => null);
|
|
63
|
+
this.offset = config.offset ?? 0;
|
|
63
64
|
this.initialRender = false;
|
|
64
65
|
this.failedNavigation = false;
|
|
65
66
|
this.alreadyScrolledTo = [];
|
|
@@ -73,16 +74,16 @@ class AutoScrollManagerPlugin {
|
|
|
73
74
|
const ypos = window.scrollY;
|
|
74
75
|
idList.forEach((id) => {
|
|
75
76
|
const element = document.getElementById(id);
|
|
76
|
-
if (type === 0
|
|
77
|
+
if (type === 0 /* ValidationError */ && element?.getAttribute("aria-invalid") === "false") {
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
79
|
-
if (type === 1) {
|
|
80
|
+
if (type === 1 /* FirstAppearance */) {
|
|
80
81
|
if (this.alreadyScrolledTo.indexOf(id) !== -1) {
|
|
81
82
|
return;
|
|
82
83
|
}
|
|
83
84
|
this.alreadyScrolledTo.push(id);
|
|
84
85
|
}
|
|
85
|
-
const epos = element
|
|
86
|
+
const epos = element?.getBoundingClientRect().top;
|
|
86
87
|
if (epos !== void 0 && (epos + ypos < highestElement.ypos || highestElement.id === "")) {
|
|
87
88
|
highestElement.id = id;
|
|
88
89
|
highestElement.ypos = ypos + epos;
|
|
@@ -91,25 +92,29 @@ class AutoScrollManagerPlugin {
|
|
|
91
92
|
return highestElement.id;
|
|
92
93
|
}
|
|
93
94
|
calculateScroll(scrollableElements) {
|
|
94
|
-
let currentScroll = 1
|
|
95
|
+
let currentScroll = 1 /* FirstAppearance */;
|
|
95
96
|
if (this.initialRender) {
|
|
96
97
|
if (this.autoScrollOnLoad) {
|
|
97
|
-
currentScroll = 0
|
|
98
|
+
currentScroll = 0 /* ValidationError */;
|
|
98
99
|
}
|
|
99
100
|
this.initialRender = false;
|
|
100
101
|
} else if (this.failedNavigation) {
|
|
101
102
|
if (this.autoFocusOnErrorField) {
|
|
102
|
-
currentScroll = 0
|
|
103
|
+
currentScroll = 0 /* ValidationError */;
|
|
103
104
|
}
|
|
104
105
|
this.failedNavigation = false;
|
|
105
106
|
}
|
|
106
107
|
const elementList = scrollableElements.get(currentScroll);
|
|
107
108
|
if (elementList) {
|
|
108
|
-
const element = this.getFirstScrollableElement(
|
|
109
|
-
|
|
109
|
+
const element = this.getFirstScrollableElement(
|
|
110
|
+
elementList,
|
|
111
|
+
currentScroll
|
|
112
|
+
);
|
|
113
|
+
return element ?? "";
|
|
110
114
|
}
|
|
111
115
|
return "";
|
|
112
116
|
}
|
|
117
|
+
// Hooks into player flow to determine what scroll targets need to be evaluated at specific lifecycle points
|
|
113
118
|
apply(player) {
|
|
114
119
|
player.hooks.flowController.tap(this.name, (fc) => {
|
|
115
120
|
fc.hooks.flow.tap(this.name, (flow) => {
|
|
@@ -129,17 +134,27 @@ class AutoScrollManagerPlugin {
|
|
|
129
134
|
}
|
|
130
135
|
applyReact(reactPlayer) {
|
|
131
136
|
reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return /* @__PURE__ */
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
const { scrollFn, getBaseElement, offset } = this;
|
|
138
|
+
function AutoScrollManagerComponent() {
|
|
139
|
+
return /* @__PURE__ */ React2.createElement(
|
|
140
|
+
AutoScrollProvider,
|
|
141
|
+
{
|
|
142
|
+
getElementToScrollTo: scrollFn,
|
|
143
|
+
getBaseElement,
|
|
144
|
+
offset
|
|
145
|
+
},
|
|
146
|
+
/* @__PURE__ */ React2.createElement(Comp, null)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return AutoScrollManagerComponent;
|
|
140
150
|
});
|
|
141
151
|
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
};
|
|
153
|
+
export {
|
|
154
|
+
AutoScrollManagerContext,
|
|
155
|
+
AutoScrollManagerPlugin,
|
|
156
|
+
AutoScrollProvider,
|
|
157
|
+
ScrollType,
|
|
158
|
+
useRegisterAsScrollable
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/scrollIntoViewWithOffset.ts
|
|
5
|
+
import { scrollTo } from "seamless-scroll-polyfill";
|
|
6
|
+
var scrollIntoViewWithOffset_default = (node, baseElement, offset) => {
|
|
7
|
+
scrollTo(window, {
|
|
8
|
+
behavior: "smooth",
|
|
9
|
+
top: node.getBoundingClientRect().top - baseElement.getBoundingClientRect().top - offset
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx
|
|
14
|
+
var AutoScrollManagerContext = React.createContext({ register: () => {
|
|
15
|
+
} });
|
|
16
|
+
var useRegisterAsScrollable = () => {
|
|
17
|
+
const { register } = React.useContext(AutoScrollManagerContext);
|
|
18
|
+
return register;
|
|
19
|
+
};
|
|
20
|
+
var AutoScrollProvider = ({
|
|
21
|
+
getElementToScrollTo,
|
|
22
|
+
getBaseElement,
|
|
23
|
+
offset,
|
|
24
|
+
children
|
|
25
|
+
}) => {
|
|
26
|
+
const [scrollableMap, setScrollableMap] = useState(/* @__PURE__ */ new Map());
|
|
27
|
+
const updateScrollableMap = (key, value) => {
|
|
28
|
+
setScrollableMap((prev) => {
|
|
29
|
+
const nm = new Map(prev);
|
|
30
|
+
if (!nm.get(key)) {
|
|
31
|
+
nm.set(key, /* @__PURE__ */ new Set());
|
|
32
|
+
}
|
|
33
|
+
nm.get(key)?.add(value);
|
|
34
|
+
return nm;
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const register = (data) => {
|
|
38
|
+
updateScrollableMap(data.type, data.ref);
|
|
39
|
+
};
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const node = document.getElementById(getElementToScrollTo(scrollableMap));
|
|
42
|
+
if (node) {
|
|
43
|
+
scrollIntoViewWithOffset_default(node, getBaseElement() || document.body, offset);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return /* @__PURE__ */ React.createElement(AutoScrollManagerContext.Provider, { value: { register } }, children);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/plugin.tsx
|
|
50
|
+
import React2 from "react";
|
|
51
|
+
var ScrollType = /* @__PURE__ */ ((ScrollType2) => {
|
|
52
|
+
ScrollType2[ScrollType2["ValidationError"] = 0] = "ValidationError";
|
|
53
|
+
ScrollType2[ScrollType2["FirstAppearance"] = 1] = "FirstAppearance";
|
|
54
|
+
ScrollType2[ScrollType2["Unknown"] = 2] = "Unknown";
|
|
55
|
+
return ScrollType2;
|
|
56
|
+
})(ScrollType || {});
|
|
57
|
+
var AutoScrollManagerPlugin = class {
|
|
58
|
+
constructor(config) {
|
|
59
|
+
this.name = "auto-scroll-manager";
|
|
60
|
+
this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;
|
|
61
|
+
this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;
|
|
62
|
+
this.getBaseElement = config.getBaseElement ?? (() => null);
|
|
63
|
+
this.offset = config.offset ?? 0;
|
|
64
|
+
this.initialRender = false;
|
|
65
|
+
this.failedNavigation = false;
|
|
66
|
+
this.alreadyScrolledTo = [];
|
|
67
|
+
this.scrollFn = this.calculateScroll.bind(this);
|
|
68
|
+
}
|
|
69
|
+
getFirstScrollableElement(idList, type) {
|
|
70
|
+
const highestElement = {
|
|
71
|
+
id: "",
|
|
72
|
+
ypos: 0
|
|
73
|
+
};
|
|
74
|
+
const ypos = window.scrollY;
|
|
75
|
+
idList.forEach((id) => {
|
|
76
|
+
const element = document.getElementById(id);
|
|
77
|
+
if (type === 0 /* ValidationError */ && element?.getAttribute("aria-invalid") === "false") {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (type === 1 /* FirstAppearance */) {
|
|
81
|
+
if (this.alreadyScrolledTo.indexOf(id) !== -1) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.alreadyScrolledTo.push(id);
|
|
85
|
+
}
|
|
86
|
+
const epos = element?.getBoundingClientRect().top;
|
|
87
|
+
if (epos !== void 0 && (epos + ypos < highestElement.ypos || highestElement.id === "")) {
|
|
88
|
+
highestElement.id = id;
|
|
89
|
+
highestElement.ypos = ypos + epos;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return highestElement.id;
|
|
93
|
+
}
|
|
94
|
+
calculateScroll(scrollableElements) {
|
|
95
|
+
let currentScroll = 1 /* FirstAppearance */;
|
|
96
|
+
if (this.initialRender) {
|
|
97
|
+
if (this.autoScrollOnLoad) {
|
|
98
|
+
currentScroll = 0 /* ValidationError */;
|
|
99
|
+
}
|
|
100
|
+
this.initialRender = false;
|
|
101
|
+
} else if (this.failedNavigation) {
|
|
102
|
+
if (this.autoFocusOnErrorField) {
|
|
103
|
+
currentScroll = 0 /* ValidationError */;
|
|
104
|
+
}
|
|
105
|
+
this.failedNavigation = false;
|
|
106
|
+
}
|
|
107
|
+
const elementList = scrollableElements.get(currentScroll);
|
|
108
|
+
if (elementList) {
|
|
109
|
+
const element = this.getFirstScrollableElement(
|
|
110
|
+
elementList,
|
|
111
|
+
currentScroll
|
|
112
|
+
);
|
|
113
|
+
return element ?? "";
|
|
114
|
+
}
|
|
115
|
+
return "";
|
|
116
|
+
}
|
|
117
|
+
// Hooks into player flow to determine what scroll targets need to be evaluated at specific lifecycle points
|
|
118
|
+
apply(player) {
|
|
119
|
+
player.hooks.flowController.tap(this.name, (fc) => {
|
|
120
|
+
fc.hooks.flow.tap(this.name, (flow) => {
|
|
121
|
+
flow.hooks.transition.tap(this.name, () => {
|
|
122
|
+
this.initialRender = true;
|
|
123
|
+
this.failedNavigation = false;
|
|
124
|
+
this.alreadyScrolledTo = [];
|
|
125
|
+
window.scroll(0, 0);
|
|
126
|
+
});
|
|
127
|
+
flow.hooks.skipTransition.intercept({
|
|
128
|
+
call: () => {
|
|
129
|
+
this.failedNavigation = true;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
applyReact(reactPlayer) {
|
|
136
|
+
reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
|
|
137
|
+
const { scrollFn, getBaseElement, offset } = this;
|
|
138
|
+
function AutoScrollManagerComponent() {
|
|
139
|
+
return /* @__PURE__ */ React2.createElement(
|
|
140
|
+
AutoScrollProvider,
|
|
141
|
+
{
|
|
142
|
+
getElementToScrollTo: scrollFn,
|
|
143
|
+
getBaseElement,
|
|
144
|
+
offset
|
|
145
|
+
},
|
|
146
|
+
/* @__PURE__ */ React2.createElement(Comp, null)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return AutoScrollManagerComponent;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
export {
|
|
154
|
+
AutoScrollManagerContext,
|
|
155
|
+
AutoScrollManagerPlugin,
|
|
156
|
+
AutoScrollProvider,
|
|
157
|
+
ScrollType,
|
|
158
|
+
useRegisterAsScrollable
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/hooks.tsx","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/scrollIntoViewWithOffset.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/auto-scroll/react/src/plugin.tsx"],"sourcesContent":["import type { PropsWithChildren } from \"react\";\nimport React, { useEffect, useState } from \"react\";\nimport scrollIntoViewWithOffset from \"./scrollIntoViewWithOffset\";\nimport type { ScrollType } from \"./index\";\n\nexport interface AutoScrollProviderProps {\n /** Return the element to scroll to based on the registered types */\n getElementToScrollTo: (\n scrollableElements: Map<ScrollType, Set<string>>,\n ) => string;\n /** Optional function to get container element, which is used for calculating offset (default: document.body) */\n getBaseElement: () => HTMLElement | undefined | null;\n /** Additional offset to be used (default: 0) */\n offset: number;\n}\n\nexport interface RegisterData {\n /** when to scroll to the target */\n type: ScrollType;\n\n /** the html id to scroll to */\n ref: string;\n}\n\nexport type ScrollFunction = (registerData: RegisterData) => void;\n\nexport const AutoScrollManagerContext = React.createContext<{\n /** function to register a scroll target */\n register: ScrollFunction;\n}>({ register: () => {} });\n\n/** hook to register as a scroll target */\nexport const useRegisterAsScrollable = (): ScrollFunction => {\n const { register } = React.useContext(AutoScrollManagerContext);\n\n return register;\n};\n\n/** Component to handle scrolling */\nexport const AutoScrollProvider = ({\n getElementToScrollTo,\n getBaseElement,\n offset,\n children,\n}: PropsWithChildren<AutoScrollProviderProps>) => {\n // Tracker for what elements are registered to be scroll targets\n // Key is the type (initial, validation, appear)\n // Value is a set of target ids\n const [scrollableMap, setScrollableMap] = useState<\n Map<ScrollType, Set<string>>\n >(new Map());\n\n /** Add a new entry as a scroll target */\n const updateScrollableMap = (key: ScrollType, value: string) => {\n setScrollableMap((prev) => {\n const nm = new Map(prev);\n\n if (!nm.get(key)) {\n nm.set(key, new Set());\n }\n\n nm.get(key)?.add(value);\n\n return nm;\n });\n };\n\n /** register a new scroll target */\n const register: ScrollFunction = (data) => {\n updateScrollableMap(data.type, data.ref);\n };\n\n useEffect(() => {\n const node = document.getElementById(getElementToScrollTo(scrollableMap));\n\n if (node) {\n scrollIntoViewWithOffset(node, getBaseElement() || document.body, offset);\n }\n });\n\n return (\n <AutoScrollManagerContext.Provider value={{ register }}>\n {children}\n </AutoScrollManagerContext.Provider>\n );\n};\n","/**\n * Scroll to the given element\n-* @param node Element to scroll to\n-* @param baseElement Container element used to calculate offset\n-* @param offset Additional offset\n */\n\nimport { scrollTo } from \"seamless-scroll-polyfill\";\n\nexport default (\n node: HTMLElement,\n baseElement: HTMLElement,\n offset: number,\n) => {\n scrollTo(window, {\n behavior: \"smooth\",\n top:\n node.getBoundingClientRect().top -\n baseElement.getBoundingClientRect().top -\n offset,\n });\n};\n","import type { ReactPlayer, ReactPlayerPlugin } from \"@player-ui/react\";\nimport type { Player } from \"@player-ui/react\";\nimport React from \"react\";\nimport { AutoScrollProvider } from \"./hooks\";\n\nexport enum ScrollType {\n ValidationError,\n FirstAppearance,\n Unknown,\n}\n\nexport interface AutoScrollManagerConfig {\n /** Config to auto-scroll on load */\n autoScrollOnLoad?: boolean;\n /** Config to auto-focus on an error */\n autoFocusOnErrorField?: boolean;\n /** Optional function to get container element, which is used for calculating offset (default: document.body) */\n getBaseElement?: () => HTMLElement | undefined | null;\n /** Additional offset to be used (default: 0) */\n offset?: number;\n}\n\n/** A plugin to manage scrolling behavior */\nexport class AutoScrollManagerPlugin implements ReactPlayerPlugin {\n name = \"auto-scroll-manager\";\n\n /** Toggles if we should auto scroll to to the first failed validation on page load */\n private autoScrollOnLoad: boolean;\n\n /** Toggles if we should auto scroll to the first failed validation on navigation failure */\n private autoFocusOnErrorField: boolean;\n\n /** tracks if its the initial page render */\n private initialRender: boolean;\n\n /** tracks if the navigation failed */\n private failedNavigation: boolean;\n\n /** function to return the base of the scrollable area */\n private getBaseElement: () => HTMLElement | undefined | null;\n\n /** static offset */\n private offset: number;\n\n /** map of scroll type to set of ids that are registered under that type */\n private alreadyScrolledTo: Array<string>;\n private scrollFn: (\n scrollableElements: Map<ScrollType, Set<string>>,\n ) => string;\n\n constructor(config: AutoScrollManagerConfig) {\n this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;\n this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;\n this.getBaseElement = config.getBaseElement ?? (() => null);\n this.offset = config.offset ?? 0;\n this.initialRender = false;\n this.failedNavigation = false;\n this.alreadyScrolledTo = [];\n this.scrollFn = this.calculateScroll.bind(this);\n }\n\n getFirstScrollableElement(idList: Set<string>, type: ScrollType) {\n const highestElement = {\n id: \"\",\n ypos: 0,\n };\n const ypos = window.scrollY;\n idList.forEach((id) => {\n const element = document.getElementById(id);\n\n // if we are looking at validation errors, make sure the element is invalid\n if (\n type === ScrollType.ValidationError &&\n element?.getAttribute(\"aria-invalid\") === \"false\"\n ) {\n return;\n }\n\n // if we are just looking at elements that just appeared, make sure we haven't\n // scrolled to them before\n if (type === ScrollType.FirstAppearance) {\n if (this.alreadyScrolledTo.indexOf(id) !== -1) {\n return;\n }\n\n this.alreadyScrolledTo.push(id);\n }\n\n const epos = element?.getBoundingClientRect().top;\n if (\n epos !== undefined &&\n (epos + ypos < highestElement.ypos || highestElement.id === \"\")\n ) {\n highestElement.id = id;\n highestElement.ypos = ypos + epos;\n }\n });\n return highestElement.id;\n }\n\n calculateScroll(scrollableElements: Map<ScrollType, Set<string>>) {\n let currentScroll = ScrollType.FirstAppearance;\n if (this.initialRender) {\n if (this.autoScrollOnLoad) {\n currentScroll = ScrollType.ValidationError;\n }\n\n this.initialRender = false;\n } else if (this.failedNavigation) {\n if (this.autoFocusOnErrorField) {\n currentScroll = ScrollType.ValidationError;\n }\n\n this.failedNavigation = false;\n }\n\n const elementList = scrollableElements.get(currentScroll);\n if (elementList) {\n const element = this.getFirstScrollableElement(\n elementList,\n currentScroll,\n );\n return element ?? \"\";\n }\n\n return \"\";\n }\n\n // Hooks into player flow to determine what scroll targets need to be evaluated at specific lifecycle points\n apply(player: Player) {\n player.hooks.flowController.tap(this.name, (fc) => {\n fc.hooks.flow.tap(this.name, (flow) => {\n flow.hooks.transition.tap(this.name, () => {\n // Reset Everything\n this.initialRender = true;\n this.failedNavigation = false;\n this.alreadyScrolledTo = [];\n // Reset scroll position for new view\n window.scroll(0, 0);\n });\n flow.hooks.skipTransition.intercept({\n call: () => {\n this.failedNavigation = true;\n },\n });\n });\n });\n }\n\n applyReact(reactPlayer: ReactPlayer) {\n reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {\n const { scrollFn, getBaseElement, offset } = this;\n\n function AutoScrollManagerComponent() {\n return (\n <AutoScrollProvider\n getElementToScrollTo={scrollFn}\n getBaseElement={getBaseElement}\n offset={offset}\n >\n <Comp />\n </AutoScrollProvider>\n );\n }\n\n return AutoScrollManagerComponent;\n });\n }\n}\n"],"mappings":"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","names":["React","ScrollType","React"]}
|