kamrify commited on
Commit
836d49f
·
1 Parent(s): 1d8c3af

Fix state being persisted

Browse files
Files changed (6) hide show
  1. index.html +33 -6
  2. src/driver.ts +3 -3
  3. src/highlight.ts +33 -16
  4. src/popover.ts +0 -1
  5. src/stage.ts +0 -3
  6. src/state.ts +10 -2
index.html CHANGED
@@ -253,7 +253,13 @@ npm install driver.js</pre
253
  import { driver } from "./src/driver.ts";
254
 
255
  document.getElementById("highlight-btn").addEventListener("click", () => {
256
- driver({ animate: true }).highlight({ element: "h1" });
 
 
 
 
 
 
257
  });
258
 
259
  document.getElementById("simple-highlight-btn").addEventListener("click", () => {
@@ -285,18 +291,39 @@ npm install driver.js</pre
285
  document.getElementById("transition-highlight-btn").addEventListener("click", () => {
286
  const driverObj = driver({ animate: true });
287
 
288
- driverObj.highlight({ element: "h1" });
 
 
 
 
 
289
 
290
  window.setTimeout(() => {
291
- driverObj.highlight({ element: ".buttons button:first-child" });
 
 
 
 
 
 
292
  }, 2000);
293
 
294
  window.setTimeout(() => {
295
- driverObj.highlight({});
 
 
 
 
 
296
  }, 4000);
297
 
298
  window.setTimeout(() => {
299
- driverObj.highlight({ element: "h2" });
 
 
 
 
 
300
  }, 6000);
301
  });
302
 
@@ -311,7 +338,7 @@ npm install driver.js</pre
311
  popover: {
312
  title: "driver.js",
313
  description: "Highlight anything, anywhere on the page",
314
- }
315
  });
316
  });
317
 
 
253
  import { driver } from "./src/driver.ts";
254
 
255
  document.getElementById("highlight-btn").addEventListener("click", () => {
256
+ driver({ animate: true }).highlight({
257
+ element: "h2",
258
+ popover: {
259
+ title: "driver.js",
260
+ description: "A lightweight, no-dependency JavaScript engine to drive user's focus across the page",
261
+ },
262
+ });
263
  });
264
 
265
  document.getElementById("simple-highlight-btn").addEventListener("click", () => {
 
291
  document.getElementById("transition-highlight-btn").addEventListener("click", () => {
292
  const driverObj = driver({ animate: true });
293
 
294
+ driverObj.highlight({
295
+ popover: {
296
+ title: "driver.js",
297
+ description: "Highlight anything, anywhere on the page",
298
+ },
299
+ });
300
 
301
  window.setTimeout(() => {
302
+ driverObj.highlight({
303
+ element: ".buttons button:first-child",
304
+ popover: {
305
+ title: "driver.js",
306
+ description: "Highlight anything, anywhere on the page",
307
+ },
308
+ });
309
  }, 2000);
310
 
311
  window.setTimeout(() => {
312
+ driverObj.highlight({
313
+ popover: {
314
+ title: "driver.js",
315
+ description: "Highlight anything, anywhere on the page",
316
+ },
317
+ });
318
  }, 4000);
319
 
320
  window.setTimeout(() => {
321
+ driverObj.highlight({
322
+ element: "h2",
323
+ popover: {
324
+ description: "driver.js",
325
+ },
326
+ });
327
  }, 6000);
328
  });
329
 
 
338
  popover: {
339
  title: "driver.js",
340
  description: "Highlight anything, anywhere on the page",
341
+ },
342
  });
343
  });
344
 
src/driver.ts CHANGED
@@ -6,7 +6,7 @@ import { destroyHighlight, highlight } from "./highlight";
6
  import { destroyEmitter, listen } from "./emitter";
7
 
8
  import "./style.css";
9
- import { getState, setState } from "./state";
10
 
11
  export type DriveStep = {
12
  element?: string | Element;
@@ -39,8 +39,6 @@ export function driver(options: Config = {}) {
39
  }
40
 
41
  function destroy() {
42
- setState("isInitialized", false);
43
-
44
  document.body.classList.remove("driver-active", "driver-fade", "driver-simple");
45
 
46
  destroyEvents();
@@ -48,6 +46,8 @@ export function driver(options: Config = {}) {
48
  destroyHighlight();
49
  destroyStage();
50
  destroyEmitter();
 
 
51
  }
52
 
53
  return {
 
6
  import { destroyEmitter, listen } from "./emitter";
7
 
8
  import "./style.css";
9
+ import { getState, resetState, setState } from "./state";
10
 
11
  export type DriveStep = {
12
  element?: string | Element;
 
39
  }
40
 
41
  function destroy() {
 
 
42
  document.body.classList.remove("driver-active", "driver-fade", "driver-simple");
43
 
44
  destroyEvents();
 
46
  destroyHighlight();
47
  destroyStage();
48
  destroyEmitter();
49
+
50
+ resetState();
51
  }
52
 
53
  return {
src/highlight.ts CHANGED
@@ -31,23 +31,32 @@ export function highlight(step: DriveStep) {
31
  const { element } = step;
32
  let elemObj = typeof element === "string" ? document.querySelector(element) : element;
33
 
 
 
 
 
34
  if (!elemObj) {
35
  elemObj = mountDummyElement();
36
  }
37
 
38
- const previousHighlight = getState("activeHighlight");
 
 
 
39
 
40
- const transferHighlightFrom = previousHighlight || elemObj;
41
  const transferHighlightTo = elemObj;
42
 
43
- transferHighlight(transferHighlightFrom, transferHighlightTo);
44
 
45
- setState("previousHighlight", transferHighlightFrom);
46
- setState("activeHighlight", transferHighlightTo);
 
 
47
  }
48
 
49
  export function refreshActiveHighlight() {
50
- const activeHighlight = getState("activeHighlight");
51
  if (!activeHighlight) {
52
  return;
53
  }
@@ -57,14 +66,28 @@ export function refreshActiveHighlight() {
57
  repositionPopover(activeHighlight);
58
  }
59
 
60
- function transferHighlight(from: Element, to: Element) {
61
  const duration = 400;
62
  const start = Date.now();
63
 
 
 
64
  // If it's the first time we're highlighting an element, we show
65
  // the popover immediately. Otherwise, we wait for the animation
66
  // to finish before showing the popover.
67
- const hasDelayedPopover = !from || from !== to;
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  hidePopover();
70
 
@@ -85,7 +108,7 @@ function transferHighlight(from: Element, to: Element) {
85
  } else {
86
  trackActiveElement(to);
87
 
88
- if (hasDelayedPopover) {
89
  renderPopover(to);
90
  }
91
 
@@ -99,7 +122,7 @@ function transferHighlight(from: Element, to: Element) {
99
  window.requestAnimationFrame(animate);
100
 
101
  bringInView(to);
102
- if (!hasDelayedPopover) {
103
  renderPopover(to);
104
  }
105
 
@@ -108,13 +131,7 @@ function transferHighlight(from: Element, to: Element) {
108
  }
109
 
110
  export function destroyHighlight() {
111
- setState("activeHighlight", undefined);
112
- setState("previousHighlight", undefined);
113
-
114
- setState("transitionCallback", undefined);
115
-
116
  document.getElementById("driver-dummy-element")?.remove();
117
-
118
  document.querySelectorAll(".driver-active-element").forEach(element => {
119
  element.classList.remove("driver-active-element");
120
  });
 
31
  const { element } = step;
32
  let elemObj = typeof element === "string" ? document.querySelector(element) : element;
33
 
34
+ // If the element is not found, we mount a 1px div
35
+ // at the center of the screen to highlight and show
36
+ // the popover on top of that. This is to show a
37
+ // modal-like highlight.
38
  if (!elemObj) {
39
  elemObj = mountDummyElement();
40
  }
41
 
42
+ // Keep track of the previous step so that we can
43
+ // animate the transition between the two steps.
44
+ setState("previousStep", getState("activeStep"));
45
+ setState("activeStep", step);
46
 
47
+ const transferHighlightFrom = getState("activeElement") || elemObj;
48
  const transferHighlightTo = elemObj;
49
 
50
+ transferHighlight(transferHighlightFrom, transferHighlightTo, step);
51
 
52
+ // Keep track of the previous element so that we can
53
+ // animate the transition between the two elements.
54
+ setState("previousElement", transferHighlightFrom);
55
+ setState("activeElement", transferHighlightTo);
56
  }
57
 
58
  export function refreshActiveHighlight() {
59
+ const activeHighlight = getState("activeElement");
60
  if (!activeHighlight) {
61
  return;
62
  }
 
66
  repositionPopover(activeHighlight);
67
  }
68
 
69
+ function transferHighlight(from: Element, to: Element, toStep: DriveStep) {
70
  const duration = 400;
71
  const start = Date.now();
72
 
73
+ const previousStep = getState("previousStep");
74
+
75
  // If it's the first time we're highlighting an element, we show
76
  // the popover immediately. Otherwise, we wait for the animation
77
  // to finish before showing the popover.
78
+ const isFirstHighlight = !from || from === to;
79
+ const hasNoPreviousPopover = previousStep && !previousStep.popover;
80
+ const isNextOrPrevDummyElement = to.id === "driver-dummy-element" || from.id === "driver-dummy-element";
81
+
82
+ const hasDelayedPopover = !isFirstHighlight && (hasNoPreviousPopover || isNextOrPrevDummyElement);
83
+
84
+ console.log("--------------------");
85
+ console.log("from", from);
86
+ console.log("to", to);
87
+ console.log("hasDelayedPopover", hasDelayedPopover);
88
+ console.log("isFirstHighlight", isFirstHighlight);
89
+ console.log("hasNoPreviousPopover", hasNoPreviousPopover);
90
+ console.log("isNextOrPrevDummyElement", isNextOrPrevDummyElement);
91
 
92
  hidePopover();
93
 
 
108
  } else {
109
  trackActiveElement(to);
110
 
111
+ if (hasDelayedPopover && toStep.popover) {
112
  renderPopover(to);
113
  }
114
 
 
122
  window.requestAnimationFrame(animate);
123
 
124
  bringInView(to);
125
+ if (!hasDelayedPopover && toStep.popover) {
126
  renderPopover(to);
127
  }
128
 
 
131
  }
132
 
133
  export function destroyHighlight() {
 
 
 
 
 
134
  document.getElementById("driver-dummy-element")?.remove();
 
135
  document.querySelectorAll(".driver-active-element").forEach(element => {
136
  element.classList.remove("driver-active-element");
137
  });
src/popover.ts CHANGED
@@ -478,5 +478,4 @@ export function destroyPopover() {
478
  }
479
 
480
  popover.wrapper.parentElement?.removeChild(popover.wrapper);
481
- setState("popover", undefined);
482
  }
 
478
  }
479
 
480
  popover.wrapper.parentElement?.removeChild(popover.wrapper);
 
481
  }
src/stage.ts CHANGED
@@ -174,8 +174,5 @@ export function destroyStage() {
174
  const stageSvg = getState("stageSvg");
175
  if (stageSvg) {
176
  stageSvg.remove();
177
- setState("stageSvg", undefined);
178
  }
179
-
180
- setState("activeStagePosition", undefined);
181
  }
 
174
  const stageSvg = getState("stageSvg");
175
  if (stageSvg) {
176
  stageSvg.remove();
 
177
  }
 
 
178
  }
src/state.ts CHANGED
@@ -1,5 +1,6 @@
1
  import { StageDefinition } from "./stage";
2
  import { PopoverDOM } from "./popover";
 
3
 
4
  export type State = {
5
  // Whether driver is initialized or not
@@ -9,10 +10,13 @@ export type State = {
9
  resizeTimeout?: number;
10
 
11
  // Used while transitioning between stages
12
- previousHighlight?: Element;
13
- activeHighlight?: Element;
14
  transitionCallback?: () => void;
15
 
 
 
 
16
  activeStagePosition?: StageDefinition;
17
  stageSvg?: SVGSVGElement;
18
 
@@ -30,3 +34,7 @@ export function getState<K extends keyof State>(key: K): State[K];
30
  export function getState<K extends keyof State>(key?: K) {
31
  return key ? currentState[key] : currentState;
32
  }
 
 
 
 
 
1
  import { StageDefinition } from "./stage";
2
  import { PopoverDOM } from "./popover";
3
+ import { DriveStep } from "./driver";
4
 
5
  export type State = {
6
  // Whether driver is initialized or not
 
10
  resizeTimeout?: number;
11
 
12
  // Used while transitioning between stages
13
+ previousElement?: Element;
14
+ activeElement?: Element;
15
  transitionCallback?: () => void;
16
 
17
+ activeStep?: DriveStep;
18
+ previousStep?: DriveStep;
19
+
20
  activeStagePosition?: StageDefinition;
21
  stageSvg?: SVGSVGElement;
22
 
 
34
  export function getState<K extends keyof State>(key?: K) {
35
  return key ? currentState[key] : currentState;
36
  }
37
+
38
+ export function resetState() {
39
+ currentState = {};
40
+ }