kamrify commited on
Commit
82a88c5
·
1 Parent(s): 8480986

Handle scrollable elements for highlighting

Browse files
Files changed (6) hide show
  1. index.html +87 -2
  2. src/config.ts +2 -0
  3. src/highlight.ts +3 -25
  4. src/math.ts +0 -11
  5. src/stage.ts +1 -1
  6. src/utils.ts +52 -0
index.html CHANGED
@@ -94,6 +94,15 @@
94
  padding: 10px;
95
  line-height: 1.75;
96
  }
 
 
 
 
 
 
 
 
 
97
  </style>
98
  </head>
99
  <body>
@@ -110,6 +119,8 @@
110
  <button id="disallow-close">Disallow Close</button>
111
  <button id="dark-highlight-btn">Super Dark Highlight</button>
112
  <button id="dim-highlight-btn">Super Dim Highlight</button>
 
 
113
  <button id="tour-btn">Start Tour</button>
114
  <button id="destroy-btn">Destroy</button>
115
  </div>
@@ -131,14 +142,14 @@
131
  off the Lights" widgets that you might have seen on video players
132
  online, etc.
133
  </p>
134
- <p>
135
  Driver.js is written in Vanilla JS, has zero dependencies and is highly
136
  customizable. It has several options allowing you to manipulate how it
137
  behaves and also provides you the hooks to manipulate the elements as
138
  they are highlighted, about to be highlighted, or deselected.
139
  </p>
140
 
141
- <h2>Installation</h2>
142
  <p>You can install it using yarn or npm, whatever you prefer.</p>
143
 
144
  <pre>
@@ -175,6 +186,62 @@ npm install driver.js</pre
175
  libero, minus molestias necessitatibus nesciunt non omnis, quasi
176
  recusandae tempore voluptates!
177
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  <p>
179
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
180
  blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
@@ -249,6 +316,24 @@ npm install driver.js</pre
249
  window.setTimeout(() => {
250
  driverObj.highlight({ element: ".buttons" });
251
  }, 1000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  });
253
 
254
  document
 
94
  padding: 10px;
95
  line-height: 1.75;
96
  }
97
+
98
+ #scrollable-area {
99
+ height: 300px;
100
+ overflow: auto;
101
+ border: 1px solid #ccc;
102
+ padding: 10px;
103
+ border-radius: 5px;
104
+ margin: 50px 0;
105
+ }
106
  </style>
107
  </head>
108
  <body>
 
119
  <button id="disallow-close">Disallow Close</button>
120
  <button id="dark-highlight-btn">Super Dark Highlight</button>
121
  <button id="dim-highlight-btn">Super Dim Highlight</button>
122
+ <button id="scrollable-area-btn">Scrollable Area</button>
123
+ <button id="inner-scroll-area-btn">Inner Scroll Area</button>
124
  <button id="tour-btn">Start Tour</button>
125
  <button id="destroy-btn">Destroy</button>
126
  </div>
 
142
  off the Lights" widgets that you might have seen on video players
143
  online, etc.
144
  </p>
145
+ <p class="second-para">
146
  Driver.js is written in Vanilla JS, has zero dependencies and is highly
147
  customizable. It has several options allowing you to manipulate how it
148
  behaves and also provides you the hooks to manipulate the elements as
149
  they are highlighted, about to be highlighted, or deselected.
150
  </p>
151
 
152
+ <h2 id="installation-head">Installation</h2>
153
  <p>You can install it using yarn or npm, whatever you prefer.</p>
154
 
155
  <pre>
 
186
  libero, minus molestias necessitatibus nesciunt non omnis, quasi
187
  recusandae tempore voluptates!
188
  </p>
189
+ <div id="scrollable-area">
190
+ <p>
191
+ First -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
192
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
193
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
194
+ quibusdam veniam! Doloribus eos id quaerat.
195
+ </p>
196
+ <p>
197
+ Second -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
198
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
199
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
200
+ quibusdam veniam! Doloribus eos id quaerat.
201
+ </p>
202
+ <p id="third-scroll-paragraph">
203
+ Third -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
204
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
205
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
206
+ quibusdam veniam! Doloribus eos id quaerat.
207
+ </p>
208
+ <p>
209
+ Fourth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
210
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
211
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
212
+ quibusdam veniam! Doloribus eos id quaerat.
213
+ </p>
214
+ <p>
215
+ Fifth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
216
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
217
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
218
+ quibusdam veniam! Doloribus eos id quaerat.
219
+ </p>
220
+ <p>
221
+ Sixth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
222
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
223
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
224
+ quibusdam veniam! Doloribus eos id quaerat.
225
+ </p>
226
+ <p>
227
+ Seventh -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
228
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
229
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
230
+ quibusdam veniam! Doloribus eos id quaerat.
231
+ </p>
232
+ <p>
233
+ Eighth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
234
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
235
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
236
+ quibusdam veniam! Doloribus eos id quaerat.
237
+ </p>
238
+ <p>
239
+ Ninth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
240
+ Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
241
+ doloremque laborum maxime necessitatibus nostrum odio, officiis
242
+ quibusdam veniam! Doloribus eos id quaerat.
243
+ </p>
244
+ </div>
245
  <p>
246
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
247
  blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
 
316
  window.setTimeout(() => {
317
  driverObj.highlight({ element: ".buttons" });
318
  }, 1000);
319
+
320
+ window.setTimeout(() => {
321
+ driverObj.highlight({ element: "#installation-head" });
322
+ }, 1500);
323
+ });
324
+
325
+ document
326
+ .getElementById("scrollable-area-btn")
327
+ .addEventListener("click", () => {
328
+ const driverObj = driver({ animate: true });
329
+ driverObj.highlight({ element: "#scrollable-area" });
330
+ });
331
+
332
+ document
333
+ .getElementById("inner-scroll-area-btn")
334
+ .addEventListener("click", () => {
335
+ const driverObj = driver({ animate: true });
336
+ driverObj.highlight({ element: "#third-scroll-paragraph" });
337
  });
338
 
339
  document
src/config.ts CHANGED
@@ -1,5 +1,6 @@
1
  export type Config = {
2
  animate?: boolean;
 
3
  allowClose?: boolean;
4
  opacity?: number;
5
  };
@@ -11,6 +12,7 @@ export function configure(config: Config = {}) {
11
  animate: true,
12
  allowClose: true,
13
  opacity: 0.7,
 
14
  ...config,
15
  };
16
  }
 
1
  export type Config = {
2
  animate?: boolean;
3
+ smoothScroll?: boolean;
4
  allowClose?: boolean;
5
  opacity?: number;
6
  };
 
12
  animate: true,
13
  allowClose: true,
14
  opacity: 0.7,
15
+ smoothScroll: true,
16
  ...config,
17
  };
18
  }
src/highlight.ts CHANGED
@@ -2,6 +2,7 @@ import { DriveStep } from "./driver";
2
  import { refreshStage, trackActiveElement, transitionStage } from "./stage";
3
  import { getConfig } from "./config";
4
  import { refreshPopover, renderPopover } from "./popover";
 
5
 
6
  let previousHighlight: Element | undefined;
7
  let activeHighlight: Element | undefined;
@@ -48,7 +49,6 @@ function transferHighlight(from: Element, to: Element) {
48
  if (getConfig("animate") && elapsed < duration) {
49
  transitionStage(elapsed, duration, from, to);
50
  } else {
51
- bringInView(to);
52
  trackActiveElement(to);
53
  renderPopover(to);
54
 
@@ -63,34 +63,12 @@ function transferHighlight(from: Element, to: Element) {
63
  currentTransitionCallback = animate;
64
  window.requestAnimationFrame(animate);
65
 
 
 
66
  from.classList.remove("driver-active-element");
67
  to.classList.add("driver-active-element");
68
  }
69
 
70
- function bringInView(element: Element) {
71
- if (!element || isElementInView(element)) {
72
- return;
73
- }
74
-
75
- element.scrollIntoView({
76
- behavior: "smooth",
77
- inline: "center",
78
- block: "center",
79
- });
80
- }
81
-
82
- function isElementInView(element: Element) {
83
- const rect = element.getBoundingClientRect();
84
-
85
- return (
86
- rect.top >= 0 &&
87
- rect.left >= 0 &&
88
- rect.bottom <=
89
- (window.innerHeight || document.documentElement.clientHeight) &&
90
- rect.right <= (window.innerWidth || document.documentElement.clientWidth)
91
- );
92
- }
93
-
94
  export function destroyHighlight() {
95
  activeHighlight = undefined;
96
  currentTransitionCallback = undefined;
 
2
  import { refreshStage, trackActiveElement, transitionStage } from "./stage";
3
  import { getConfig } from "./config";
4
  import { refreshPopover, renderPopover } from "./popover";
5
+ import { bringInView } from "./utils";
6
 
7
  let previousHighlight: Element | undefined;
8
  let activeHighlight: Element | undefined;
 
49
  if (getConfig("animate") && elapsed < duration) {
50
  transitionStage(elapsed, duration, from, to);
51
  } else {
 
52
  trackActiveElement(to);
53
  renderPopover(to);
54
 
 
63
  currentTransitionCallback = animate;
64
  window.requestAnimationFrame(animate);
65
 
66
+ bringInView(to);
67
+
68
  from.classList.remove("driver-active-element");
69
  to.classList.add("driver-active-element");
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  export function destroyHighlight() {
73
  activeHighlight = undefined;
74
  currentTransitionCallback = undefined;
src/math.ts DELETED
@@ -1,11 +0,0 @@
1
- export function easeInOutQuad(
2
- elapsed: number,
3
- initialValue: number,
4
- amountOfChange: number,
5
- duration: number
6
- ): number {
7
- if ((elapsed /= duration / 2) < 1) {
8
- return (amountOfChange / 2) * elapsed * elapsed + initialValue;
9
- }
10
- return (-amountOfChange / 2) * (--elapsed * (elapsed - 2) - 1) + initialValue;
11
- }
 
 
 
 
 
 
 
 
 
 
 
 
src/stage.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { easeInOutQuad } from "./math";
2
  import { onDriverClick } from "./events";
3
  import { trigger } from "./hooks";
4
  import { getConfig } from "./config";
 
1
+ import { easeInOutQuad } from "./utils";
2
  import { onDriverClick } from "./events";
3
  import { trigger } from "./hooks";
4
  import { getConfig } from "./config";
src/utils.ts ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { getConfig } from "./config";
2
+
3
+ export function easeInOutQuad(
4
+ elapsed: number,
5
+ initialValue: number,
6
+ amountOfChange: number,
7
+ duration: number
8
+ ): number {
9
+ if ((elapsed /= duration / 2) < 1) {
10
+ return (amountOfChange / 2) * elapsed * elapsed + initialValue;
11
+ }
12
+ return (-amountOfChange / 2) * (--elapsed * (elapsed - 2) - 1) + initialValue;
13
+ }
14
+
15
+ export function bringInView(element: Element) {
16
+ if (!element || isElementInView(element)) {
17
+ return;
18
+ }
19
+
20
+ const shouldSmoothScroll = getConfig("smoothScroll");
21
+
22
+ element.scrollIntoView({
23
+ // Removing the smooth scrolling for elements which exist inside the scrollable parent
24
+ // This was causing the highlight to not properly render
25
+ behavior:
26
+ !shouldSmoothScroll || hasScrollableParent(element) ? "auto" : "smooth",
27
+ inline: "center",
28
+ block: "center",
29
+ });
30
+ }
31
+
32
+ function hasScrollableParent(e: Element) {
33
+ if (!e || !e.parentElement) {
34
+ return;
35
+ }
36
+
37
+ const parent = e.parentElement as HTMLElement & { scrollTopMax?: number };
38
+
39
+ return parent.scrollHeight > parent.clientHeight;
40
+ }
41
+
42
+ function isElementInView(element: Element) {
43
+ const rect = element.getBoundingClientRect();
44
+
45
+ return (
46
+ rect.top >= 0 &&
47
+ rect.left >= 0 &&
48
+ rect.bottom <=
49
+ (window.innerHeight || document.documentElement.clientHeight) &&
50
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
51
+ );
52
+ }