@player-ui/auto-scroll-manager-plugin-react 0.4.0 → 0.4.1-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/index.cjs.js CHANGED
@@ -3,12 +3,18 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
- var scrollIntoView = require('smooth-scroll-into-view-if-needed');
6
+ var seamlessScrollPolyfill = require('seamless-scroll-polyfill');
7
7
 
8
8
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
9
 
10
10
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
11
- var scrollIntoView__default = /*#__PURE__*/_interopDefaultLegacy(scrollIntoView);
11
+
12
+ var scrollIntoViewWithOffset = (node, baseElement, offset) => {
13
+ seamlessScrollPolyfill.scrollTo(window, {
14
+ behavior: "smooth",
15
+ top: node.getBoundingClientRect().top - baseElement.getBoundingClientRect().top - offset
16
+ });
17
+ };
12
18
 
13
19
  const AutoScrollManagerContext = React__default["default"].createContext({ register: () => {
14
20
  } });
@@ -18,6 +24,8 @@ const useRegisterAsScrollable = () => {
18
24
  };
19
25
  const AutoScrollProvider = ({
20
26
  getElementToScrollTo,
27
+ getBaseElement,
28
+ offset,
21
29
  children
22
30
  }) => {
23
31
  const [scrollableMap, setScrollableMap] = React.useState(new Map());
@@ -38,10 +46,7 @@ const AutoScrollProvider = ({
38
46
  React.useEffect(() => {
39
47
  const node = document.getElementById(getElementToScrollTo(scrollableMap));
40
48
  if (node) {
41
- scrollIntoView__default["default"](node, {
42
- block: "center",
43
- inline: "center"
44
- });
49
+ scrollIntoViewWithOffset(node, getBaseElement() || document.body, offset);
45
50
  }
46
51
  });
47
52
  return /* @__PURE__ */ React__default["default"].createElement(AutoScrollManagerContext.Provider, {
@@ -58,9 +63,11 @@ exports.ScrollType = void 0;
58
63
  class AutoScrollManagerPlugin {
59
64
  constructor(config) {
60
65
  this.name = "auto-scroll-manager";
61
- var _a, _b;
66
+ var _a, _b, _c, _d;
62
67
  this.autoScrollOnLoad = (_a = config.autoScrollOnLoad) != null ? _a : false;
63
68
  this.autoFocusOnErrorField = (_b = config.autoFocusOnErrorField) != null ? _b : false;
69
+ this.getBaseElement = (_c = config.getBaseElement) != null ? _c : () => null;
70
+ this.offset = (_d = config.offset) != null ? _d : 0;
64
71
  this.initialRender = false;
65
72
  this.failedNavigation = false;
66
73
  this.alreadyScrolledTo = [];
@@ -84,9 +91,9 @@ class AutoScrollManagerPlugin {
84
91
  this.alreadyScrolledTo.push(id);
85
92
  }
86
93
  const epos = element == null ? void 0 : element.getBoundingClientRect().top;
87
- if (epos && (epos + ypos > highestElement.ypos || highestElement.ypos === 0)) {
94
+ if (epos !== void 0 && (epos + ypos < highestElement.ypos || highestElement.id === "")) {
88
95
  highestElement.id = id;
89
- highestElement.ypos = ypos - epos;
96
+ highestElement.ypos = ypos + epos;
90
97
  }
91
98
  });
92
99
  return highestElement.id;
@@ -118,6 +125,7 @@ class AutoScrollManagerPlugin {
118
125
  this.initialRender = true;
119
126
  this.failedNavigation = false;
120
127
  this.alreadyScrolledTo = [];
128
+ window.scroll(0, 0);
121
129
  });
122
130
  flow.hooks.skipTransition.intercept({
123
131
  call: () => {
@@ -130,9 +138,11 @@ class AutoScrollManagerPlugin {
130
138
  applyReact(reactPlayer) {
131
139
  reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
132
140
  return () => {
133
- const { scrollFn } = this;
141
+ const { scrollFn, getBaseElement, offset } = this;
134
142
  return /* @__PURE__ */ React__default["default"].createElement(AutoScrollProvider, {
135
- getElementToScrollTo: scrollFn
143
+ getElementToScrollTo: scrollFn,
144
+ getBaseElement,
145
+ offset
136
146
  }, /* @__PURE__ */ React__default["default"].createElement(Comp, null));
137
147
  };
138
148
  });
package/dist/index.d.ts CHANGED
@@ -5,6 +5,10 @@ import { Player } from '@player-ui/player';
5
5
  interface AutoScrollProviderProps {
6
6
  /** Return the element to scroll to based on the registered types */
7
7
  getElementToScrollTo: (scrollableElements: Map<ScrollType, Set<string>>) => string;
8
+ /** Optional function to get container element, which is used for calculating offset (default: document.body) */
9
+ getBaseElement: () => HTMLElement | undefined | null;
10
+ /** Additional offset to be used (default: 0) */
11
+ offset: number;
8
12
  }
9
13
  interface RegisterData {
10
14
  /** when to scroll to the target */
@@ -20,7 +24,7 @@ declare const AutoScrollManagerContext: React.Context<{
20
24
  /** hook to register as a scroll target */
21
25
  declare const useRegisterAsScrollable: () => ScrollFunction;
22
26
  /** Component to handle scrolling */
23
- declare const AutoScrollProvider: ({ getElementToScrollTo, children, }: PropsWithChildren<AutoScrollProviderProps>) => JSX.Element;
27
+ declare const AutoScrollProvider: ({ getElementToScrollTo, getBaseElement, offset, children, }: PropsWithChildren<AutoScrollProviderProps>) => JSX.Element;
24
28
 
25
29
  declare enum ScrollType {
26
30
  ValidationError = 0,
@@ -32,6 +36,10 @@ interface AutoScrollManagerConfig {
32
36
  autoScrollOnLoad?: boolean;
33
37
  /** Config to auto-focus on an error */
34
38
  autoFocusOnErrorField?: boolean;
39
+ /** Optional function to get container element, which is used for calculating offset (default: document.body) */
40
+ getBaseElement?: () => HTMLElement | undefined | null;
41
+ /** Additional offset to be used (default: 0) */
42
+ offset?: number;
35
43
  }
36
44
  /** A plugin to manage scrolling behavior */
37
45
  declare class AutoScrollManagerPlugin implements ReactPlayerPlugin {
@@ -44,6 +52,10 @@ declare class AutoScrollManagerPlugin implements ReactPlayerPlugin {
44
52
  private initialRender;
45
53
  /** tracks if the navigation failed */
46
54
  private failedNavigation;
55
+ /** function to return the base of the scrollable area */
56
+ private getBaseElement;
57
+ /** static offset */
58
+ private offset;
47
59
  /** map of scroll type to set of ids that are registered under that type */
48
60
  private alreadyScrolledTo;
49
61
  private scrollFn;
package/dist/index.esm.js CHANGED
@@ -1,5 +1,12 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import scrollIntoView from 'smooth-scroll-into-view-if-needed';
2
+ import { scrollTo } from 'seamless-scroll-polyfill';
3
+
4
+ var scrollIntoViewWithOffset = (node, baseElement, offset) => {
5
+ scrollTo(window, {
6
+ behavior: "smooth",
7
+ top: node.getBoundingClientRect().top - baseElement.getBoundingClientRect().top - offset
8
+ });
9
+ };
3
10
 
4
11
  const AutoScrollManagerContext = React.createContext({ register: () => {
5
12
  } });
@@ -9,6 +16,8 @@ const useRegisterAsScrollable = () => {
9
16
  };
10
17
  const AutoScrollProvider = ({
11
18
  getElementToScrollTo,
19
+ getBaseElement,
20
+ offset,
12
21
  children
13
22
  }) => {
14
23
  const [scrollableMap, setScrollableMap] = useState(new Map());
@@ -29,10 +38,7 @@ const AutoScrollProvider = ({
29
38
  useEffect(() => {
30
39
  const node = document.getElementById(getElementToScrollTo(scrollableMap));
31
40
  if (node) {
32
- scrollIntoView(node, {
33
- block: "center",
34
- inline: "center"
35
- });
41
+ scrollIntoViewWithOffset(node, getBaseElement() || document.body, offset);
36
42
  }
37
43
  });
38
44
  return /* @__PURE__ */ React.createElement(AutoScrollManagerContext.Provider, {
@@ -49,9 +55,11 @@ var ScrollType;
49
55
  class AutoScrollManagerPlugin {
50
56
  constructor(config) {
51
57
  this.name = "auto-scroll-manager";
52
- var _a, _b;
58
+ var _a, _b, _c, _d;
53
59
  this.autoScrollOnLoad = (_a = config.autoScrollOnLoad) != null ? _a : false;
54
60
  this.autoFocusOnErrorField = (_b = config.autoFocusOnErrorField) != null ? _b : false;
61
+ this.getBaseElement = (_c = config.getBaseElement) != null ? _c : () => null;
62
+ this.offset = (_d = config.offset) != null ? _d : 0;
55
63
  this.initialRender = false;
56
64
  this.failedNavigation = false;
57
65
  this.alreadyScrolledTo = [];
@@ -75,9 +83,9 @@ class AutoScrollManagerPlugin {
75
83
  this.alreadyScrolledTo.push(id);
76
84
  }
77
85
  const epos = element == null ? void 0 : element.getBoundingClientRect().top;
78
- if (epos && (epos + ypos > highestElement.ypos || highestElement.ypos === 0)) {
86
+ if (epos !== void 0 && (epos + ypos < highestElement.ypos || highestElement.id === "")) {
79
87
  highestElement.id = id;
80
- highestElement.ypos = ypos - epos;
88
+ highestElement.ypos = ypos + epos;
81
89
  }
82
90
  });
83
91
  return highestElement.id;
@@ -109,6 +117,7 @@ class AutoScrollManagerPlugin {
109
117
  this.initialRender = true;
110
118
  this.failedNavigation = false;
111
119
  this.alreadyScrolledTo = [];
120
+ window.scroll(0, 0);
112
121
  });
113
122
  flow.hooks.skipTransition.intercept({
114
123
  call: () => {
@@ -121,9 +130,11 @@ class AutoScrollManagerPlugin {
121
130
  applyReact(reactPlayer) {
122
131
  reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
123
132
  return () => {
124
- const { scrollFn } = this;
133
+ const { scrollFn, getBaseElement, offset } = this;
125
134
  return /* @__PURE__ */ React.createElement(AutoScrollProvider, {
126
- getElementToScrollTo: scrollFn
135
+ getElementToScrollTo: scrollFn,
136
+ getBaseElement,
137
+ offset
127
138
  }, /* @__PURE__ */ React.createElement(Comp, null));
128
139
  };
129
140
  });
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@player-ui/auto-scroll-manager-plugin-react",
3
- "version": "0.4.0",
3
+ "version": "0.4.1-next.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org"
7
7
  },
8
8
  "peerDependencies": {
9
- "@player-ui/react": "0.4.0"
9
+ "@player-ui/react": "0.4.1-next.0"
10
10
  },
11
11
  "dependencies": {
12
- "smooth-scroll-into-view-if-needed": "1.1.32",
12
+ "seamless-scroll-polyfill": "2.3.3",
13
13
  "@babel/runtime": "7.15.4"
14
14
  },
15
15
  "main": "dist/index.cjs.js",
@@ -53,6 +53,14 @@
53
53
  {
54
54
  "name": "Kelly Harrop",
55
55
  "url": "https://github.com/kharrop"
56
+ },
57
+ {
58
+ "name": "Alejandro Fimbres",
59
+ "url": "https://github.com/lexfm"
60
+ },
61
+ {
62
+ "name": "Rafael Campos",
63
+ "url": "https://github.com/rafbcampos"
56
64
  }
57
65
  ]
58
66
  }
package/src/hooks.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { PropsWithChildren } from 'react';
2
2
  import React, { useEffect, useState } from 'react';
3
- import scrollIntoView from 'smooth-scroll-into-view-if-needed';
3
+ import scrollIntoViewWithOffset from './scrollIntoViewWithOffset';
4
4
  import type { ScrollType } from './index';
5
5
 
6
6
  export interface AutoScrollProviderProps {
@@ -8,6 +8,10 @@ export interface AutoScrollProviderProps {
8
8
  getElementToScrollTo: (
9
9
  scrollableElements: Map<ScrollType, Set<string>>
10
10
  ) => string;
11
+ /** Optional function to get container element, which is used for calculating offset (default: document.body) */
12
+ getBaseElement: () => HTMLElement | undefined | null;
13
+ /** Additional offset to be used (default: 0) */
14
+ offset: number;
11
15
  }
12
16
 
13
17
  export interface RegisterData {
@@ -35,6 +39,8 @@ export const useRegisterAsScrollable = (): ScrollFunction => {
35
39
  /** Component to handle scrolling */
36
40
  export const AutoScrollProvider = ({
37
41
  getElementToScrollTo,
42
+ getBaseElement,
43
+ offset,
38
44
  children,
39
45
  }: PropsWithChildren<AutoScrollProviderProps>) => {
40
46
  // Tracker for what elements are registered to be scroll targets
@@ -68,10 +74,7 @@ export const AutoScrollProvider = ({
68
74
  const node = document.getElementById(getElementToScrollTo(scrollableMap));
69
75
 
70
76
  if (node) {
71
- scrollIntoView(node, {
72
- block: 'center',
73
- inline: 'center',
74
- });
77
+ scrollIntoViewWithOffset(node, getBaseElement() || document.body, offset);
75
78
  }
76
79
  });
77
80
 
package/src/plugin.tsx CHANGED
@@ -14,6 +14,10 @@ export interface AutoScrollManagerConfig {
14
14
  autoScrollOnLoad?: boolean;
15
15
  /** Config to auto-focus on an error */
16
16
  autoFocusOnErrorField?: boolean;
17
+ /** Optional function to get container element, which is used for calculating offset (default: document.body) */
18
+ getBaseElement?: () => HTMLElement | undefined | null;
19
+ /** Additional offset to be used (default: 0) */
20
+ offset?: number;
17
21
  }
18
22
 
19
23
  /** A plugin to manage scrolling behavior */
@@ -32,6 +36,12 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
32
36
  /** tracks if the navigation failed */
33
37
  private failedNavigation: boolean;
34
38
 
39
+ /** function to return the base of the scrollable area */
40
+ private getBaseElement: () => HTMLElement | undefined | null;
41
+
42
+ /** static offset */
43
+ private offset: number;
44
+
35
45
  /** map of scroll type to set of ids that are registered under that type */
36
46
  private alreadyScrolledTo: Array<string>;
37
47
  private scrollFn: (
@@ -41,6 +51,8 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
41
51
  constructor(config: AutoScrollManagerConfig) {
42
52
  this.autoScrollOnLoad = config.autoScrollOnLoad ?? false;
43
53
  this.autoFocusOnErrorField = config.autoFocusOnErrorField ?? false;
54
+ this.getBaseElement = config.getBaseElement ?? (() => null);
55
+ this.offset = config.offset ?? 0;
44
56
  this.initialRender = false;
45
57
  this.failedNavigation = false;
46
58
  this.alreadyScrolledTo = [];
@@ -75,22 +87,19 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
75
87
  }
76
88
 
77
89
  const epos = element?.getBoundingClientRect().top;
78
-
79
90
  if (
80
- epos &&
81
- (epos + ypos > highestElement.ypos || highestElement.ypos === 0)
91
+ epos !== undefined &&
92
+ (epos + ypos < highestElement.ypos || highestElement.id === '')
82
93
  ) {
83
94
  highestElement.id = id;
84
- highestElement.ypos = ypos - epos;
95
+ highestElement.ypos = ypos + epos;
85
96
  }
86
97
  });
87
-
88
98
  return highestElement.id;
89
99
  }
90
100
 
91
101
  calculateScroll(scrollableElements: Map<ScrollType, Set<string>>) {
92
102
  let currentScroll = ScrollType.FirstAppearance;
93
-
94
103
  if (this.initialRender) {
95
104
  if (this.autoScrollOnLoad) {
96
105
  currentScroll = ScrollType.ValidationError;
@@ -106,13 +115,11 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
106
115
  }
107
116
 
108
117
  const elementList = scrollableElements.get(currentScroll);
109
-
110
118
  if (elementList) {
111
119
  const element = this.getFirstScrollableElement(
112
120
  elementList,
113
121
  currentScroll
114
122
  );
115
-
116
123
  return element ?? '';
117
124
  }
118
125
 
@@ -128,6 +135,8 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
128
135
  this.initialRender = true;
129
136
  this.failedNavigation = false;
130
137
  this.alreadyScrolledTo = [];
138
+ // Reset scroll position for new view
139
+ window.scroll(0, 0);
131
140
  });
132
141
  flow.hooks.skipTransition.intercept({
133
142
  call: () => {
@@ -141,10 +150,13 @@ export class AutoScrollManagerPlugin implements ReactPlayerPlugin {
141
150
  applyReact(reactPlayer: ReactPlayer) {
142
151
  reactPlayer.hooks.webComponent.tap(this.name, (Comp) => {
143
152
  return () => {
144
- const { scrollFn } = this;
145
-
153
+ const { scrollFn, getBaseElement, offset } = this;
146
154
  return (
147
- <AutoScrollProvider getElementToScrollTo={scrollFn}>
155
+ <AutoScrollProvider
156
+ getElementToScrollTo={scrollFn}
157
+ getBaseElement={getBaseElement}
158
+ offset={offset}
159
+ >
148
160
  <Comp />
149
161
  </AutoScrollProvider>
150
162
  );
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Scroll to the given element
3
+ -* @param node Element to scroll to
4
+ -* @param baseElement Container element used to calculate offset
5
+ -* @param offset Additional offset
6
+ */
7
+
8
+ import { scrollTo } from 'seamless-scroll-polyfill';
9
+
10
+ export default (
11
+ node: HTMLElement,
12
+ baseElement: HTMLElement,
13
+ offset: number
14
+ ) => {
15
+ scrollTo(window, {
16
+ behavior: 'smooth',
17
+ top:
18
+ node.getBoundingClientRect().top -
19
+ baseElement.getBoundingClientRect().top -
20
+ offset,
21
+ });
22
+ };