alessandro trinca tornidor commited on
Commit
e1fa40c
·
2 Parent(s): 5ac3315 1a36d65

chore: merge tag 1.3.5 from https://github.com/kamranahmedse/driver.js

Browse files
README.md CHANGED
@@ -14,11 +14,11 @@ license: mit
14
  <a href="https://github.com/kamranahmedse/driver.js/blob/master/license">
15
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg" />
16
  </a>
17
- <a href="https://npmjs.org/package/driver.js">
18
- <img src="https://img.shields.io/npm/v/driver.js.svg" alt="version" />
19
  </a>
20
  <a href="https://npmjs.org/package/driver.js">
21
- <img src="https://img.shields.io/npm/dt/driver.js.svg" alt="downloads" />
22
  </a>
23
  </p>
24
 
 
14
  <a href="https://github.com/kamranahmedse/driver.js/blob/master/license">
15
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg" />
16
  </a>
17
+ <a href="https://www.jsdelivr.com/package/npm/driver.js">
18
+ <img src="https://data.jsdelivr.com/v1/package/npm/driver.js/badge?style=rounded" alt="jsdelivr hits" />
19
  </a>
20
  <a href="https://npmjs.org/package/driver.js">
21
+ <img src="https://img.shields.io/npm/dm/driver.js" alt="downloads" />
22
  </a>
23
  </p>
24
 
docs/src/components/CodeSample.tsx CHANGED
@@ -53,7 +53,7 @@ export function CodeSample(props: CodeSampleProps) {
53
  const { heading, id, children, buttonText = "Show me an Example", className, config, highlight, tour } = props;
54
 
55
  if (id === "demo-hook-theme") {
56
- config!.onPopoverRendered = attachFirstButton;
57
  }
58
 
59
  function onClick() {
 
53
  const { heading, id, children, buttonText = "Show me an Example", className, config, highlight, tour } = props;
54
 
55
  if (id === "demo-hook-theme") {
56
+ config!.onPopoverRender = attachFirstButton;
57
  }
58
 
59
  function onClick() {
docs/src/components/Examples.astro CHANGED
@@ -499,7 +499,7 @@ import { ExampleButton } from "./ExampleButton";
499
  element: '#customizing-popover',
500
  popover: {
501
  title: "Customizing Popover",
502
- description: "Add your own class using `popoverClass` or use `onPopoverRendered` to get full control over the popover. <br /><br /> Visit these pages which cover <a class='font-medium underline' href='/docs/styling-popover'>styling</a> and <a class='font-medium underline' href='/docs/buttons'>customizing popovers</a> in detail.",
503
  side: 'top',
504
  align: 'start'
505
  }
 
499
  element: '#customizing-popover',
500
  popover: {
501
  title: "Customizing Popover",
502
+ description: "Add your own class using `popoverClass` or use `onPopoverRender` to get full control over the popover. <br /><br /> Visit these pages which cover <a class='font-medium underline' href='/docs/styling-popover'>styling</a> and <a class='font-medium underline' href='/docs/buttons'>customizing popovers</a> in detail.",
503
  side: 'top',
504
  align: 'start'
505
  }
docs/src/components/Features.astro ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ import { Earth, Smartphone, Settings, Feather, Code2, Layers, Keyboard } from "lucide-react";
3
+ import Container from "./Container.astro";
4
+ ---
5
+
6
+ <div class="py-0 mb-16 bg-white">
7
+ <Container>
8
+ <div class="max-w-screen-lg">
9
+ <h2 class="text-4xl md:text-5xl lg:text-6xl font-bold text-gray-900 mb-4 md:mb-6">Nothing else like it</h2>
10
+ <p class="text-base md:text-xl lg:text-2xl text-black mb-10 md:mb-14 lg:mb-16">
11
+ Lightweight with no external dependencies, supports all major browsers and is highly customizable.
12
+ </p>
13
+ </div>
14
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 md:gap-10 lg:gap-4">
15
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
16
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
17
+ <Earth className="w-6 h-6 text-black lg:w-7 lg:h-7" />
18
+ </div>
19
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Browser Support</h3>
20
+ <p class="text-gray-600 md:text-lg">
21
+ Works in all modern browsers including Chrome, IE9+, Safari, Firefox and Opera
22
+ </p>
23
+ </div>
24
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
25
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
26
+ <Smartphone className="w-6 h-6 text-black lg:w-7 lg:h-7" />
27
+ </div>
28
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Mobile Ready</h3>
29
+ <p class="text-gray-600 md:text-lg">Works on desktop, tablets and mobile devices</p>
30
+ </div>
31
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
32
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
33
+ <Settings className="w-6 h-6 text-black lg:w-7 lg:h-7" />
34
+ </div>
35
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Highly Customizable</h3>
36
+ <p class="text-gray-600 md:text-lg">Powerful API that allows you to customize it to your needs</p>
37
+ </div>
38
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
39
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
40
+ <Feather className="w-6 h-6 text-black lg:w-7 lg:h-7" />
41
+ </div>
42
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Lightweight</h3>
43
+ <p class="text-gray-600 md:text-lg">
44
+ Only 5KB minified, compared to other libraries which are typically >12KB minified
45
+ </p>
46
+ </div>
47
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
48
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
49
+ <Code2 className="w-6 h-6 text-black lg:w-7 lg:h-7" />
50
+ </div>
51
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">No Dependencies</h3>
52
+ <p class="text-gray-600 md:text-lg">Simple to use with absolutely no external dependencies</p>
53
+ </div>
54
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
55
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
56
+ <Layers className="w-6 h-6 text-black lg:w-7 lg:h-7" />
57
+ </div>
58
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Feature Rich</h3>
59
+ <p class="text-gray-600 md:text-lg">Create powerful feature introductions for your web applications</p>
60
+ </div>
61
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
62
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
63
+ <span class="w-6 h-6 text-black lg:w-7 lg:h-7 font-black">MIT</span>
64
+ </div>
65
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">MIT License</h3>
66
+ <p class="text-gray-600 md:text-lg">Free for both personal and commercial use</p>
67
+ </div>
68
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
69
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
70
+ <Keyboard className="w-6 h-6 text-black lg:w-7 lg:h-7" />
71
+ </div>
72
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Keyboard Control</h3>
73
+ <p class="text-gray-600 md:text-lg">All actions can be controlled via keyboard</p>
74
+ </div>
75
+ <div class="group bg-yellow-50 p-6 rounded-xl transition-colors">
76
+ <div class="flex justify-center items-center mb-4 w-12 h-12 rounded-xl bg-yellow-300 lg:h-14 lg:w-14">
77
+ <span class="w-6 h-6 text-black lg:w-7 lg:h-7 font-black">ALL</span>
78
+ </div>
79
+ <h3 class="mb-3 text-xl md:text-2xl font-bold text-black">Highlight Anything</h3>
80
+ <p class="text-gray-600 md:text-lg">Highlight any element on the page</p>
81
+ </div>
82
+ </div>
83
+ </Container>
84
+ </div>
docs/src/components/HeroSection.astro CHANGED
@@ -1,26 +1,52 @@
1
  ---
2
  import Container from "./Container.astro";
3
  ---
4
- <div class="bg-yellow-300">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  <Container>
6
  <div class="py-10 md:py-14 lg:py-20 flex justify-start items-center gap-4">
7
  <div class="flex-grow" data-hero-text>
8
  <h1 data-driver-name class="text-7xl md:text-8xl lg:text-9xl mb-2 md:mb-3 lg:mb-4 font-bold">driver.js</h1>
9
- <p data-driver-tagline class="text-md md:text-2xl lg:text-3xl">Product tours, highlights, contextual help and more.</p>
 
 
 
10
  <div class="mt-4 md:mt-8 lg:mt-10 flex flex-col sm:flex-row gap-2 items-stretch">
11
- <button data-demo-tour class="bg-black rounded-xl py-2 md:py-3 px-6 font-medium text-white text-lg md:text-xl focus:outline-0 hover:bg-gray-800 focus:bg-gray-800">
12
- Show Demo Tour
 
 
 
13
  </button>
14
- <a href="/docs/installation"
15
- data-docs-link
16
- class="bg-white rounded-xl py-2 md:py-3 px-6 font-medium text-black text-lg md:text-xl focus:outline-0 border-4 border-black text-center hover:bg-gray-200 focus:bg-gray-200">
 
 
17
  Get Started
18
  </a>
19
  </div>
20
  </div>
21
  <div class="flex-shrink-0 hidden sm:flex">
22
- <img src="/driver.svg" alt="Hero Image" class="sm:h-48 md:h-60 lg:h-72" />
23
  </div>
24
  </div>
25
  </Container>
26
- </div>
 
1
  ---
2
  import Container from "./Container.astro";
3
  ---
4
+
5
+ <div class="bg-white border-b border-gray-100 select-none">
6
+ <Container>
7
+ <div class="flex items-center justify-between h-16">
8
+ <a href="/" class="flex items-center justify-end text-xl font-bold text-gray-900 font-semibold gap-2.5">
9
+ <img src="/favicon.svg" alt="driver.js logo" class="h-10" />
10
+ driver.js
11
+ </a>
12
+ <span class="flex items-center gap-7">
13
+ <a href="/docs/installation" class="hover:underline underline-offset-4 text-lg font-medium text-gray-900">
14
+ <span class="hidden sm:inline">Documentation</span>
15
+ <span class="inline sm:hidden">Docs</span>
16
+ </a>
17
+ <a href="https://github.com/kamranahmedse/driver.js" target="_blank" class="hover:underline underline-offset-4 text-lg font-medium text-gray-900">GitHub</a>
18
+ </span>
19
+ </div>
20
+ </Container>
21
+ </div>
22
+ <div class="bg-yellow-300/80 overflow-hidden via-transparent">
23
  <Container>
24
  <div class="py-10 md:py-14 lg:py-20 flex justify-start items-center gap-4">
25
  <div class="flex-grow" data-hero-text>
26
  <h1 data-driver-name class="text-7xl md:text-8xl lg:text-9xl mb-2 md:mb-3 lg:mb-4 font-bold">driver.js</h1>
27
+ <p data-driver-tagline class="text-base md:text-2xl lg:text-3xl !leading-normal">
28
+ Lightweight JavaScript library for product tours, highlights, and contextual help to guide users through your
29
+ product.
30
+ </p>
31
  <div class="mt-4 md:mt-8 lg:mt-10 flex flex-col sm:flex-row gap-2 items-stretch">
32
+ <button
33
+ data-demo-tour
34
+ class="bg-black rounded-xl py-2 md:py-3 px-6 font-medium text-white text-lg md:text-xl focus:outline-0 hover:bg-gray-800 focus:bg-gray-800"
35
+ >
36
+ Show Demo
37
  </button>
38
+ <a
39
+ href="/docs/installation"
40
+ data-docs-link
41
+ class="bg-white rounded-xl py-2 md:py-3 px-6 font-medium text-black text-lg md:text-xl focus:outline-0 border-2 border-black text-center hover:bg-gray-200 focus:bg-gray-200"
42
+ >
43
  Get Started
44
  </a>
45
  </div>
46
  </div>
47
  <div class="flex-shrink-0 hidden sm:flex">
48
+ <img src="/driver.svg" alt="driver.js image" class="sm:h-48 md:h-60 lg:h-72" />
49
  </div>
50
  </div>
51
  </Container>
52
+ </div>
docs/src/components/OpenSourceLove.astro CHANGED
@@ -4,7 +4,7 @@ import { getFormattedStars } from "../lib/github";
4
 
5
  const starCount = getFormattedStars('kamranahmedse/driver.js');
6
  ---
7
- <div class="py-10 md:py-12 lg:py-24 bg-white text-black border-t-2 border-t-black">
8
  <Container>
9
  <div class="flex items-center">
10
  <div>
 
4
 
5
  const starCount = getFormattedStars('kamranahmedse/driver.js');
6
  ---
7
+ <div class="py-10 md:py-12 lg:py-24 bg-white text-black border-t">
8
  <Container>
9
  <div class="flex items-center">
10
  <div>
docs/src/content/guides/configuration.mdx CHANGED
@@ -73,7 +73,7 @@ type Config = {
73
  // PopoverDOM is an object with references to
74
  // the popover DOM elements such as buttons
75
  // title, descriptions, body, container etc.
76
- onPopoverRender?: (popover: PopoverDOM, options: { config: Config; state: State }) => void;
77
 
78
  // Hooks to run before and after highlighting
79
  // each step. Each hook receives the following
@@ -82,9 +82,10 @@ type Config = {
82
  // - step: The step object configured for the step
83
  // - options.config: The current configuration options
84
  // - options.state: The current state of the driver
85
- onHighlightStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
86
- onHighlighted?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
87
- onDeselected?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
 
88
 
89
  // Hooks to run before and after the driver
90
  // is destroyed. Each hook receives
@@ -93,8 +94,9 @@ type Config = {
93
  // - step: The step object configured for the currently active
94
  // - options.config: The current configuration options
95
  // - options.state: The current state of the driver
96
- onDestroyStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
97
- onDestroyed?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
 
98
 
99
  // Hooks to run on button clicks. Each hook receives
100
  // the following parameters:
@@ -102,9 +104,10 @@ type Config = {
102
  // - step: The step object configured for the step
103
  // - options.config: The current configuration options
104
  // - options.state: The current state of the driver
105
- onNextClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
106
- onPrevClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
107
- onCloseClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
 
108
  };
109
  ```
110
 
@@ -167,7 +170,7 @@ type Popover = {
167
  // Parameter is an object with references to
168
  // the popover DOM elements such as buttons
169
  // title, descriptions, body, etc.
170
- onPopoverRender?: (popover: PopoverDOM, options: { config: Config; state: State }) => void;
171
 
172
  // Callbacks for button clicks. You can use
173
  // these to add custom behavior to the buttons.
@@ -176,9 +179,10 @@ type Popover = {
176
  // - step: The step object configured for the step
177
  // - options.config: The current configuration options
178
  // - options.state: The current state of the driver
179
- onNextClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void
180
- onPrevClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void
181
- onCloseClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void
 
182
  }
183
  ```
184
 
@@ -208,9 +212,10 @@ type DriveStep = {
208
  // - step: The step object configured for the step
209
  // - options.config: The current configuration options
210
  // - options.state: The current state of the driver
211
- onDeselected?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
212
- onHighlightStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
213
- onHighlighted?: (element?: Element, step: DriveStep, options: { config: Config; state: State }) => void;
 
214
  }
215
  ```
216
 
 
73
  // PopoverDOM is an object with references to
74
  // the popover DOM elements such as buttons
75
  // title, descriptions, body, container etc.
76
+ onPopoverRender?: (popover: PopoverDOM, options: { config: Config; state: State, driver: Driver }) => void;
77
 
78
  // Hooks to run before and after highlighting
79
  // each step. Each hook receives the following
 
82
  // - step: The step object configured for the step
83
  // - options.config: The current configuration options
84
  // - options.state: The current state of the driver
85
+ // - options.driver: Current driver object
86
+ onHighlightStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
87
+ onHighlighted?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
88
+ onDeselected?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
89
 
90
  // Hooks to run before and after the driver
91
  // is destroyed. Each hook receives
 
94
  // - step: The step object configured for the currently active
95
  // - options.config: The current configuration options
96
  // - options.state: The current state of the driver
97
+ // - options.driver: Current driver object
98
+ onDestroyStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
99
+ onDestroyed?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
100
 
101
  // Hooks to run on button clicks. Each hook receives
102
  // the following parameters:
 
104
  // - step: The step object configured for the step
105
  // - options.config: The current configuration options
106
  // - options.state: The current state of the driver
107
+ // - options.driver: Current driver object
108
+ onNextClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
109
+ onPrevClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
110
+ onCloseClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
111
  };
112
  ```
113
 
 
170
  // Parameter is an object with references to
171
  // the popover DOM elements such as buttons
172
  // title, descriptions, body, etc.
173
+ onPopoverRender?: (popover: PopoverDOM, options: { config: Config; state: State, driver: Driver }) => void;
174
 
175
  // Callbacks for button clicks. You can use
176
  // these to add custom behavior to the buttons.
 
179
  // - step: The step object configured for the step
180
  // - options.config: The current configuration options
181
  // - options.state: The current state of the driver
182
+ // - options.driver: Current driver object
183
+ onNextClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void
184
+ onPrevClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void
185
+ onCloseClick?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void
186
  }
187
  ```
188
 
 
212
  // - step: The step object configured for the step
213
  // - options.config: The current configuration options
214
  // - options.state: The current state of the driver
215
+ // - options.driver: Current driver object
216
+ onDeselected?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
217
+ onHighlightStarted?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
218
+ onHighlighted?: (element?: Element, step: DriveStep, options: { config: Config; state: State, driver: Driver }) => void;
219
  }
220
  ```
221
 
docs/src/content/guides/installation.mdx CHANGED
@@ -20,8 +20,8 @@ yarn add driver.js
20
  Alternatively, you can use CDN and include the script in your HTML file:
21
 
22
  ```html
23
- <script src="https://cdn.jsdelivr.net/npm/driver.js@1.0.1/dist/driver.js.iife.js"></script>
24
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/driver.js@1.0.1/dist/driver.css"/>
25
  ```
26
 
27
  ## Start Using
 
20
  Alternatively, you can use CDN and include the script in your HTML file:
21
 
22
  ```html
23
+ <script src="https://cdn.jsdelivr.net/npm/driver.js@latest/dist/driver.js.iife.js"></script>
24
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/driver.js@latest/dist/driver.css"/>
25
  ```
26
 
27
  ## Start Using
docs/src/layouts/BaseLayout.astro CHANGED
@@ -1,111 +1,115 @@
1
  ---
2
  import Analytics from "../components/Analytics/Analytics.astro";
3
  export interface Props {
4
- title: string;
 
 
5
  }
6
 
7
- export interface BaseLayoutProps extends Props {
8
- permalink?: string;
9
- title?: string;
10
- description?: string;
11
- }
12
-
13
- const { permalink = '', title = "Driver.js", description = "A light-weight, no-dependency, vanilla JavaScript library to drive user's focus across the page." } = Astro.props;
14
-
15
  ---
16
 
17
- <!DOCTYPE html>
18
  <html lang="en">
19
- <head>
20
- <meta charset="UTF-8" />
21
-
22
- <title>{ title }</title>
23
- <meta name="robots" content="index,follow"/>
24
- <meta name="description" itemprop="description" content={description}/>
25
-
26
- <link href={`https://driverjs.com${permalink}`} rel="canonical">
27
-
28
- <meta content="Kamran Ahmed" name=author>
29
- <meta content="summary_large_image" name="twitter:card">
30
- <meta content="@kamrify" name="twitter:creator">
31
- <meta content="1200" property="og:image:width">
32
- <meta content="630" property="og:image:height">
33
- <meta content="https://driverjs.com/og-img.png" property="og:image">
34
- <meta content="driverjs.com" property="og:image:alt">
35
- <meta content="driverjs.com" property="og:site_name">
36
- <meta content="Driver.js" property="og:title">
37
- <meta content="A light-weight, no-dependency, vanilla JavaScript library to drive user's focus across the page." property=og:description>
38
- <meta content="website" property="og:type">
39
- <meta content="https://driverjs.com/" property="og:url">
40
-
41
- <meta name="viewport" content="width=device-width" />
42
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
43
-
44
- <style is:global>
45
- .driver-popover.driverjs-theme {
46
- background-color: #fde047;
47
- color: #000;
48
- }
49
-
50
- .driver-popover.driverjs-theme .driver-popover-title {
51
- font-size: 20px;
52
- }
53
-
54
- .driver-popover.driverjs-theme .driver-popover-title,
55
- .driver-popover.driverjs-theme .driver-popover-description,
56
- .driver-popover.driverjs-theme .driver-popover-progress-text {
57
- color: #000;
58
- }
59
-
60
- .driver-popover.driverjs-theme button {
61
- flex: 1;
62
- text-align: center;
63
- background-color: #000;
64
- color: #ffffff;
65
- border: 2px solid #000;
66
- text-shadow: none;
67
- font-size: 14px;
68
- padding: 5px 8px;
69
- border-radius: 6px;
70
- }
71
-
72
- .driver-popover.driverjs-theme button:focus, .driver-popover.driverjs-theme button:hover {
73
- background-color: #424242;
74
- color: #ffffff;
75
- }
76
-
77
- .driver-popover.driverjs-theme .driver-popover-navigation-btns {
78
- justify-content: space-between;
79
- gap: 3px;
80
- }
81
-
82
- .driver-popover.driverjs-theme .driver-popover-close-btn {
83
- color: #9b9b9b;
84
- }
85
-
86
- .driver-popover.driverjs-theme .driver-popover-close-btn:hover {
87
- color: #000;
88
- }
89
-
90
- .driver-popover.driverjs-theme .driver-popover-arrow-side-left.driver-popover-arrow {
91
- border-left-color: #fde047;
92
- }
93
-
94
- .driver-popover.driverjs-theme .driver-popover-arrow-side-right.driver-popover-arrow {
95
- border-right-color: #fde047;
96
- }
97
-
98
- .driver-popover.driverjs-theme .driver-popover-arrow-side-top.driver-popover-arrow {
99
- border-top-color: #fde047;
100
- }
101
-
102
- .driver-popover.driverjs-theme .driver-popover-arrow-side-bottom.driver-popover-arrow {
103
- border-bottom-color: #fde047;
104
- }
105
- </style>
106
- </head>
107
- <body>
108
- <slot />
109
- <Analytics />
110
- </body>
111
- </html>
 
 
 
 
 
 
1
  ---
2
  import Analytics from "../components/Analytics/Analytics.astro";
3
  export interface Props {
4
+ permalink?: string;
5
+ title?: string;
6
+ description?: string;
7
  }
8
 
9
+ const {
10
+ permalink = "",
11
+ title = "driver.js",
12
+ description = "A light-weight, no-dependency, vanilla JavaScript library to drive user's focus across the page.",
13
+ } = Astro.props;
 
 
 
14
  ---
15
 
16
+ <!doctype html>
17
  <html lang="en">
18
+ <head>
19
+ <meta charset="UTF-8" />
20
+
21
+ <title>{title}</title>
22
+ <meta name="robots" content="index,follow" />
23
+ <meta name="description" itemprop="description" content={description} />
24
+
25
+ <link href={`https://driverjs.com${permalink}`} rel="canonical" />
26
+
27
+ <meta content="Kamran Ahmed" name="author" />
28
+ <meta content="summary_large_image" name="twitter:card" />
29
+ <meta content="@kamrify" name="twitter:creator" />
30
+ <meta content="1200" property="og:image:width" />
31
+ <meta content="630" property="og:image:height" />
32
+ <meta content="https://driverjs.com/og-img.png" property="og:image" />
33
+ <meta content="driverjs.com" property="og:image:alt" />
34
+ <meta content="driverjs.com" property="og:site_name" />
35
+ <meta content="Driver.js" property="og:title" />
36
+ <meta
37
+ content="A light-weight, no-dependency, vanilla JavaScript library to drive user's focus across the page."
38
+ property="og:description"
39
+ />
40
+ <meta content="website" property="og:type" />
41
+ <meta content="https://driverjs.com/" property="og:url" />
42
+
43
+ <meta name="viewport" content="width=device-width" />
44
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
45
+
46
+ <style is:global>
47
+ .driver-popover.driverjs-theme {
48
+ background-color: #fde047;
49
+ color: #000;
50
+ }
51
+
52
+ .driver-popover.driverjs-theme .driver-popover-title {
53
+ font-size: 20px;
54
+ }
55
+
56
+ .driver-popover.driverjs-theme .driver-popover-title,
57
+ .driver-popover.driverjs-theme .driver-popover-description,
58
+ .driver-popover.driverjs-theme .driver-popover-progress-text {
59
+ color: #000;
60
+ }
61
+
62
+ .driver-popover.driverjs-theme button {
63
+ flex: 1;
64
+ text-align: center;
65
+ background-color: #000;
66
+ color: #ffffff;
67
+ border: 1px solid #000;
68
+ text-shadow: none;
69
+ font-size: 14px;
70
+ padding: 5px 8px;
71
+ border-radius: 6px;
72
+ }
73
+
74
+ .driver-popover.driverjs-theme button:focus,
75
+ .driver-popover.driverjs-theme button:hover {
76
+ background-color: #000;
77
+ opacity: 0.8;
78
+ color: #ffffff;
79
+ }
80
+
81
+ .driver-popover.driverjs-theme .driver-popover-navigation-btns {
82
+ justify-content: space-between;
83
+ gap: 3px;
84
+ }
85
+
86
+ .driver-popover.driverjs-theme .driver-popover-close-btn {
87
+ color: #9b9b9b;
88
+ }
89
+
90
+ .driver-popover.driverjs-theme .driver-popover-close-btn:hover {
91
+ color: #000;
92
+ }
93
+
94
+ .driver-popover.driverjs-theme .driver-popover-arrow-side-left.driver-popover-arrow {
95
+ border-left-color: #fde047;
96
+ }
97
+
98
+ .driver-popover.driverjs-theme .driver-popover-arrow-side-right.driver-popover-arrow {
99
+ border-right-color: #fde047;
100
+ }
101
+
102
+ .driver-popover.driverjs-theme .driver-popover-arrow-side-top.driver-popover-arrow {
103
+ border-top-color: #fde047;
104
+ }
105
+
106
+ .driver-popover.driverjs-theme .driver-popover-arrow-side-bottom.driver-popover-arrow {
107
+ border-bottom-color: #fde047;
108
+ }
109
+ </style>
110
+ </head>
111
+ <body>
112
+ <slot />
113
+ <Analytics />
114
+ </body>
115
+ </html>
docs/src/pages/index.astro CHANGED
@@ -9,7 +9,7 @@ import Examples from "../components/Examples.astro";
9
  import UsecaseList from "../components/UsecaseList.astro";
10
  import OpenSourceLove from "../components/OpenSourceLove.astro";
11
  ---
12
- <BaseLayout>
13
  <HeroSection />
14
  <div
15
  class="bg-white overflow-x-hidden overflow-y-hidden relative h-[48px] md:h-[56px] lg:h-[64px] border-b-2 border-b-black"
 
9
  import UsecaseList from "../components/UsecaseList.astro";
10
  import OpenSourceLove from "../components/OpenSourceLove.astro";
11
  ---
12
+ <BaseLayout title="driver.js">
13
  <HeroSection />
14
  <div
15
  class="bg-white overflow-x-hidden overflow-y-hidden relative h-[48px] md:h-[56px] lg:h-[64px] border-b-2 border-b-black"
index.html CHANGED
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
@@ -166,6 +166,8 @@
166
  <p>given below are the examples of simple `highlight`</p>
167
  <div class="buttons">
168
  <button id="highlight-btn">Animated Highlight</button>
 
 
169
  <button id="simple-highlight-btn">Simple Highlight</button>
170
  <button id="transition-highlight-btn">Transition Highlight</button>
171
  <button id="disallow-close">Disallow Close</button>
@@ -388,7 +390,7 @@ npm install driver.js</pre
388
  },
389
  },
390
  {
391
- element: '.buttons',
392
  popover: {
393
  title: "Buttons",
394
  description: "Here are some buttons",
@@ -468,13 +470,17 @@ npm install driver.js</pre
468
  disableActiveInteraction: true,
469
  showProgress: true,
470
  progressText: "{{current}} of {{total}} done",
471
- onPopoverRender: (popover) => {
472
- popover.title.innerHTML = `${driverObj.getActiveIndex()} ${driverObj.hasNextStep() ? 'Yes' : 'No'} ${driverObj.hasPreviousStep() ? 'Yes' : 'No'}`
473
- popover.description.innerHTML = `${driverObj.isFirstStep() ? 'Yes' : 'No'} ${driverObj.isLastStep() ? 'Yes' : 'No'}`
 
 
 
 
474
 
475
  console.log(driverObj.getActiveIndex());
476
  console.log(driverObj.getActiveStep());
477
- }
478
  });
479
 
480
  driverObj.drive(4);
@@ -491,16 +497,16 @@ npm install driver.js</pre
491
  {
492
  element: "h1",
493
  popover: {
494
- description: "This is a new description"
495
- }
496
  },
497
  {
498
  element: "p",
499
  popover: {
500
- description: "This is another new description"
501
- }
502
- }
503
- ])
504
 
505
  driverObj.drive();
506
  });
@@ -517,16 +523,16 @@ npm install driver.js</pre
517
  {
518
  element: "h1",
519
  popover: {
520
- description: "This is a new description"
521
- }
522
  },
523
  {
524
  element: "p",
525
  popover: {
526
- description: "This is another new description"
527
- }
528
- }
529
- ])
530
 
531
  driverObj.drive();
532
  });
@@ -624,7 +630,7 @@ npm install driver.js</pre
624
  document.getElementById("basic-tour").addEventListener("click", () => {
625
  const driverObj = driver({
626
  showProgress: true,
627
- showButtons: ["next", 'previous', 'close'],
628
  steps: basicTourSteps,
629
  });
630
 
@@ -667,6 +673,10 @@ npm install driver.js</pre
667
  title: "Next and Close",
668
  showButtons: ["close", "next"],
669
  description: "This one only has next and close buttons, nothing else.",
 
 
 
 
670
  },
671
  });
672
  });
@@ -835,10 +845,10 @@ npm install driver.js</pre
835
  driverObj.destroy();
836
  },
837
  steps: [
838
- { popover: { title: "Some title", description: "Some description" }},
839
- { popover: { title: "Another title", description: "Some description" }},
840
- { popover: { title: "Yet another title", description: "Some description" }},
841
- ]
842
  });
843
 
844
  driverObj.drive();
@@ -856,10 +866,10 @@ npm install driver.js</pre
856
  });
857
  },
858
  steps: [
859
- { popover: { title: "Some title", description: "Some description" }},
860
- { popover: { title: "Another title", description: "Some description" }},
861
- { popover: { title: "Yet another title", description: "Some description" }},
862
- ]
863
  });
864
 
865
  driverObj.drive();
@@ -902,6 +912,30 @@ npm install driver.js</pre
902
  }, 2000);
903
  });
904
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
905
  document.getElementById("highlight-btn").addEventListener("click", () => {
906
  driver({
907
  animate: true,
@@ -1103,7 +1137,7 @@ npm install driver.js</pre
1103
  document.getElementById("click-overlay-to-next").addEventListener("click", () => {
1104
  const driverObj = driver({
1105
  animate: true,
1106
- overlayClickBehavior: 'nextStep',
1107
  steps: basicTourSteps,
1108
  });
1109
 
 
1
+ <!doctype html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
 
166
  <p>given below are the examples of simple `highlight`</p>
167
  <div class="buttons">
168
  <button id="highlight-btn">Animated Highlight</button>
169
+ <button id="buggy-highlight-btn">Buggy Highlight</button>
170
+ <button id="off-screen-highlight-btn">Off Screen Highlight</button>
171
  <button id="simple-highlight-btn">Simple Highlight</button>
172
  <button id="transition-highlight-btn">Transition Highlight</button>
173
  <button id="disallow-close">Disallow Close</button>
 
390
  },
391
  },
392
  {
393
+ element: ".buttons",
394
  popover: {
395
  title: "Buttons",
396
  description: "Here are some buttons",
 
470
  disableActiveInteraction: true,
471
  showProgress: true,
472
  progressText: "{{current}} of {{total}} done",
473
+ onPopoverRender: popover => {
474
+ popover.title.innerHTML = `${driverObj.getActiveIndex()} ${driverObj.hasNextStep() ? "Yes" : "No"} ${
475
+ driverObj.hasPreviousStep() ? "Yes" : "No"
476
+ }`;
477
+ popover.description.innerHTML = `${driverObj.isFirstStep() ? "Yes" : "No"} ${
478
+ driverObj.isLastStep() ? "Yes" : "No"
479
+ }`;
480
 
481
  console.log(driverObj.getActiveIndex());
482
  console.log(driverObj.getActiveStep());
483
+ },
484
  });
485
 
486
  driverObj.drive(4);
 
497
  {
498
  element: "h1",
499
  popover: {
500
+ description: "This is a new description",
501
+ },
502
  },
503
  {
504
  element: "p",
505
  popover: {
506
+ description: "This is another new description",
507
+ },
508
+ },
509
+ ]);
510
 
511
  driverObj.drive();
512
  });
 
523
  {
524
  element: "h1",
525
  popover: {
526
+ description: "This is a new description",
527
+ },
528
  },
529
  {
530
  element: "p",
531
  popover: {
532
+ description: "This is another new description",
533
+ },
534
+ },
535
+ ]);
536
 
537
  driverObj.drive();
538
  });
 
630
  document.getElementById("basic-tour").addEventListener("click", () => {
631
  const driverObj = driver({
632
  showProgress: true,
633
+ showButtons: ["next", "previous", "close"],
634
  steps: basicTourSteps,
635
  });
636
 
 
673
  title: "Next and Close",
674
  showButtons: ["close", "next"],
675
  description: "This one only has next and close buttons, nothing else.",
676
+ onNextClick: (step, element, opts) => {
677
+ console.log("Next Clicked", step, element, opts);
678
+ opts.driver.destroy();
679
+ },
680
  },
681
  });
682
  });
 
845
  driverObj.destroy();
846
  },
847
  steps: [
848
+ { popover: { title: "Some title", description: "Some description" } },
849
+ { popover: { title: "Another title", description: "Some description" } },
850
+ { popover: { title: "Yet another title", description: "Some description" } },
851
+ ],
852
  });
853
 
854
  driverObj.drive();
 
866
  });
867
  },
868
  steps: [
869
+ { popover: { title: "Some title", description: "Some description" } },
870
+ { popover: { title: "Another title", description: "Some description" } },
871
+ { popover: { title: "Yet another title", description: "Some description" } },
872
+ ],
873
  });
874
 
875
  driverObj.drive();
 
912
  }, 2000);
913
  });
914
 
915
+ document.getElementById("buggy-highlight-btn").addEventListener("click", () => {
916
+ driver().highlight({
917
+ element: ".page-header h1 sup",
918
+ popover: {
919
+ title: "Buggy Highlight",
920
+ description: "Unlike the older version, new version doesn't work with z-indexes so no more positional issues.",
921
+ side: "bottom",
922
+ align: "start",
923
+ },
924
+ });
925
+ });
926
+
927
+ document.getElementById("off-screen-highlight-btn").addEventListener("click", () => {
928
+ driver().highlight({
929
+ element: ".container",
930
+ popover: {
931
+ title: "Buggy Highlight",
932
+ description: "Unlike the older version, new version doesn't work with z-indexes so no more positional issues.",
933
+ side: "bottom",
934
+ align: "start",
935
+ },
936
+ });
937
+ });
938
+
939
  document.getElementById("highlight-btn").addEventListener("click", () => {
940
  driver({
941
  animate: true,
 
1137
  document.getElementById("click-overlay-to-next").addEventListener("click", () => {
1138
  const driverObj = driver({
1139
  animate: true,
1140
+ overlayClickBehavior: "nextStep",
1141
  steps: basicTourSteps,
1142
  });
1143
 
package.json CHANGED
@@ -2,7 +2,7 @@
2
  "name": "@trincadev/driver.js",
3
  "license": "MIT",
4
  "private": false,
5
- "version": "1.3.1-trincadev.2",
6
  "main": "./dist/driver.js.cjs",
7
  "module": "./dist/driver.js.mjs",
8
  "types": "./dist/driver.js.d.ts",
@@ -25,8 +25,9 @@
25
  "import": "./dist/driver.js.mjs"
26
  },
27
  "./dist/driver.css": {
 
28
  "import": "./dist/driver.css",
29
- "require": "./dist/driver.css"
30
  }
31
  },
32
  "scripts": {
 
2
  "name": "@trincadev/driver.js",
3
  "license": "MIT",
4
  "private": false,
5
+ "version": "1.3.5-trincadev.1",
6
  "main": "./dist/driver.js.cjs",
7
  "module": "./dist/driver.js.mjs",
8
  "types": "./dist/driver.js.d.ts",
 
25
  "import": "./dist/driver.js.mjs"
26
  },
27
  "./dist/driver.css": {
28
+ "require": "./dist/driver.css",
29
  "import": "./dist/driver.css",
30
+ "default": "./dist/driver.css"
31
  }
32
  },
33
  "scripts": {
src/config.ts CHANGED
@@ -1,8 +1,12 @@
1
- import { DriveStep } from "./driver";
2
  import { AllowedButtons, PopoverDOM } from "./popover";
3
  import { State } from "./state";
4
 
5
- export type DriverHook = (element: Element | undefined, step: DriveStep, opts: { config: Config; state: State }) => void;
 
 
 
 
6
 
7
  export type Config = {
8
  steps?: DriveStep[];
@@ -12,7 +16,7 @@ export type Config = {
12
  overlayOpacity?: number;
13
  smoothScroll?: boolean;
14
  allowClose?: boolean;
15
- overlayClickBehavior?: 'close' | 'nextStep';
16
  stagePadding?: number;
17
  stageRadius?: number;
18
 
@@ -34,7 +38,7 @@ export type Config = {
34
  doneBtnText?: string;
35
 
36
  // Called after the popover is rendered
37
- onPopoverRender?: (popover: PopoverDOM, opts: { config: Config; state: State }) => void;
38
 
39
  // State based callbacks, called upon state changes
40
  onHighlightStarted?: DriverHook;
@@ -50,12 +54,13 @@ export type Config = {
50
  };
51
 
52
  let currentConfig: Config = {};
 
53
 
54
  export function configure(config: Config = {}) {
55
  currentConfig = {
56
  animate: true,
57
  allowClose: true,
58
- overlayClickBehavior: 'close',
59
  overlayOpacity: 0.7,
60
  smoothScroll: false,
61
  disableActiveInteraction: false,
@@ -75,3 +80,11 @@ export function getConfig<K extends keyof Config>(key: K): Config[K];
75
  export function getConfig<K extends keyof Config>(key?: K) {
76
  return key ? currentConfig[key] : currentConfig;
77
  }
 
 
 
 
 
 
 
 
 
1
+ import { Driver, DriveStep } from "./driver";
2
  import { AllowedButtons, PopoverDOM } from "./popover";
3
  import { State } from "./state";
4
 
5
+ export type DriverHook = (
6
+ element: Element | undefined,
7
+ step: DriveStep,
8
+ opts: { config: Config; state: State; driver: Driver }
9
+ ) => void;
10
 
11
  export type Config = {
12
  steps?: DriveStep[];
 
16
  overlayOpacity?: number;
17
  smoothScroll?: boolean;
18
  allowClose?: boolean;
19
+ overlayClickBehavior?: "close" | "nextStep";
20
  stagePadding?: number;
21
  stageRadius?: number;
22
 
 
38
  doneBtnText?: string;
39
 
40
  // Called after the popover is rendered
41
+ onPopoverRender?: (popover: PopoverDOM, opts: { config: Config; state: State, driver: Driver }) => void;
42
 
43
  // State based callbacks, called upon state changes
44
  onHighlightStarted?: DriverHook;
 
54
  };
55
 
56
  let currentConfig: Config = {};
57
+ let currentDriver: Driver;
58
 
59
  export function configure(config: Config = {}) {
60
  currentConfig = {
61
  animate: true,
62
  allowClose: true,
63
+ overlayClickBehavior: "close",
64
  overlayOpacity: 0.7,
65
  smoothScroll: false,
66
  disableActiveInteraction: false,
 
80
  export function getConfig<K extends keyof Config>(key?: K) {
81
  return key ? currentConfig[key] : currentConfig;
82
  }
83
+
84
+ export function setCurrentDriver(driver: Driver) {
85
+ currentDriver = driver;
86
+ }
87
+
88
+ export function getCurrentDriver() {
89
+ return currentDriver;
90
+ }
src/driver.ts CHANGED
@@ -1,7 +1,7 @@
1
  import { AllowedButtons, destroyPopover, Popover } from "./popover";
2
  import { destroyOverlay } from "./overlay";
3
  import { destroyEvents, initEvents, requireRefresh } from "./events";
4
- import { Config, configure, DriverHook, getConfig } from "./config";
5
  import { destroyHighlight, highlight } from "./highlight";
6
  import { destroyEmitter, listen } from "./emitter";
7
  import { getState, resetState, setState } from "./state";
@@ -16,7 +16,31 @@ export type DriveStep = {
16
  disableActiveInteraction?: boolean;
17
  };
18
 
19
- export function driver(options: Config = {}) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  configure(options);
21
 
22
  function handleClose() {
@@ -103,6 +127,7 @@ export function driver(options: Config = {}) {
103
  return onPrevClick(activeElement, activeStep, {
104
  config: getConfig(),
105
  state: getState(),
 
106
  });
107
  }
108
 
@@ -127,6 +152,7 @@ export function driver(options: Config = {}) {
127
  return onNextClick(activeElement, activeStep, {
128
  config: getConfig(),
129
  state: getState(),
 
130
  });
131
  }
132
 
@@ -241,6 +267,7 @@ export function driver(options: Config = {}) {
241
  onDestroyStarted(isActiveDummyElement ? undefined : activeElement, activeStep!, {
242
  config: getConfig(),
243
  state: getState(),
 
244
  });
245
  return;
246
  }
@@ -264,6 +291,7 @@ export function driver(options: Config = {}) {
264
  onDeselected(isActiveDummyElement ? undefined : activeElement, activeStep, {
265
  config: getConfig(),
266
  state: getState(),
 
267
  });
268
  }
269
 
@@ -271,6 +299,7 @@ export function driver(options: Config = {}) {
271
  onDestroyed(isActiveDummyElement ? undefined : activeElement, activeStep, {
272
  config: getConfig(),
273
  state: getState(),
 
274
  });
275
  }
276
  }
@@ -280,7 +309,7 @@ export function driver(options: Config = {}) {
280
  }
281
  }
282
 
283
- return {
284
  isActive: () => getState("isInitialized") || false,
285
  refresh: requireRefresh,
286
  drive: (stepIndex: number = 0) => {
@@ -316,13 +345,13 @@ export function driver(options: Config = {}) {
316
  const steps = getConfig("steps") || [];
317
  const activeIndex = getState("activeIndex");
318
 
319
- return activeIndex !== undefined && steps[activeIndex + 1];
320
  },
321
  hasPreviousStep: () => {
322
  const steps = getConfig("steps") || [];
323
  const activeIndex = getState("activeIndex");
324
 
325
- return activeIndex !== undefined && steps[activeIndex - 1];
326
  },
327
  highlight: (step: DriveStep) => {
328
  init();
@@ -342,6 +371,8 @@ export function driver(options: Config = {}) {
342
  destroy(false);
343
  },
344
  };
345
- }
346
 
347
- export type Driver = ReturnType<typeof driver>;
 
 
 
 
1
  import { AllowedButtons, destroyPopover, Popover } from "./popover";
2
  import { destroyOverlay } from "./overlay";
3
  import { destroyEvents, initEvents, requireRefresh } from "./events";
4
+ import { Config, configure, DriverHook, getConfig, getCurrentDriver, setCurrentDriver } from "./config";
5
  import { destroyHighlight, highlight } from "./highlight";
6
  import { destroyEmitter, listen } from "./emitter";
7
  import { getState, resetState, setState } from "./state";
 
16
  disableActiveInteraction?: boolean;
17
  };
18
 
19
+ export interface Driver {
20
+ isActive: () => boolean;
21
+ refresh: () => void;
22
+ drive: (stepIndex?: number) => void;
23
+ setConfig: (config: Config) => void;
24
+ setSteps: (steps: DriveStep[]) => void;
25
+ getConfig: () => Config;
26
+ getState: (key?: string) => any;
27
+ getActiveIndex: () => number | undefined;
28
+ isFirstStep: () => boolean;
29
+ isLastStep: () => boolean;
30
+ getActiveStep: () => DriveStep | undefined;
31
+ getActiveElement: () => Element | undefined;
32
+ getPreviousElement: () => Element | undefined;
33
+ getPreviousStep: () => DriveStep | undefined;
34
+ moveNext: () => void;
35
+ movePrevious: () => void;
36
+ moveTo: (index: number) => void;
37
+ hasNextStep: () => boolean;
38
+ hasPreviousStep: () => boolean;
39
+ highlight: (step: DriveStep) => void;
40
+ destroy: () => void;
41
+ }
42
+
43
+ export function driver(options: Config = {}): Driver {
44
  configure(options);
45
 
46
  function handleClose() {
 
127
  return onPrevClick(activeElement, activeStep, {
128
  config: getConfig(),
129
  state: getState(),
130
+ driver: getCurrentDriver(),
131
  });
132
  }
133
 
 
152
  return onNextClick(activeElement, activeStep, {
153
  config: getConfig(),
154
  state: getState(),
155
+ driver: getCurrentDriver(),
156
  });
157
  }
158
 
 
267
  onDestroyStarted(isActiveDummyElement ? undefined : activeElement, activeStep!, {
268
  config: getConfig(),
269
  state: getState(),
270
+ driver: getCurrentDriver(),
271
  });
272
  return;
273
  }
 
291
  onDeselected(isActiveDummyElement ? undefined : activeElement, activeStep, {
292
  config: getConfig(),
293
  state: getState(),
294
+ driver: getCurrentDriver(),
295
  });
296
  }
297
 
 
299
  onDestroyed(isActiveDummyElement ? undefined : activeElement, activeStep, {
300
  config: getConfig(),
301
  state: getState(),
302
+ driver: getCurrentDriver(),
303
  });
304
  }
305
  }
 
309
  }
310
  }
311
 
312
+ const api: Driver = {
313
  isActive: () => getState("isInitialized") || false,
314
  refresh: requireRefresh,
315
  drive: (stepIndex: number = 0) => {
 
345
  const steps = getConfig("steps") || [];
346
  const activeIndex = getState("activeIndex");
347
 
348
+ return activeIndex !== undefined && !!steps[activeIndex + 1];
349
  },
350
  hasPreviousStep: () => {
351
  const steps = getConfig("steps") || [];
352
  const activeIndex = getState("activeIndex");
353
 
354
+ return activeIndex !== undefined && !!steps[activeIndex - 1];
355
  },
356
  highlight: (step: DriveStep) => {
357
  init();
 
371
  destroy(false);
372
  },
373
  };
 
374
 
375
+ setCurrentDriver(api);
376
+
377
+ return api;
378
+ }
src/highlight.ts CHANGED
@@ -1,6 +1,6 @@
1
  import { DriveStep } from "./driver";
2
  import { refreshOverlay, trackActiveElement, transitionStage } from "./overlay";
3
- import { getConfig } from "./config";
4
  import { hidePopover, renderPopover, repositionPopover } from "./popover";
5
  import { bringInView } from "./utils";
6
  import { getState, setState } from "./state";
@@ -71,7 +71,6 @@ export function refreshActiveHighlight() {
71
  repositionPopover(activeHighlight, activeStep);
72
  }
73
 
74
-
75
  function transferHighlight(toElement: Element, toStep: DriveStep) {
76
  const duration = 400;
77
  const start = Date.now();
@@ -98,6 +97,7 @@ function transferHighlight(toElement: Element, toStep: DriveStep) {
98
  deselectedHook(isFromDummyElement ? undefined : fromElement, fromStep!, {
99
  config,
100
  state,
 
101
  });
102
  }
103
 
@@ -105,6 +105,7 @@ function transferHighlight(toElement: Element, toStep: DriveStep) {
105
  highlightStartedHook(isToDummyElement ? undefined : toElement, toStep, {
106
  config,
107
  state,
 
108
  });
109
  }
110
 
@@ -146,6 +147,7 @@ function transferHighlight(toElement: Element, toStep: DriveStep) {
146
  highlightedHook(isToDummyElement ? undefined : toElement, toStep, {
147
  config: getConfig(),
148
  state: getState(),
 
149
  });
150
  }
151
 
 
1
  import { DriveStep } from "./driver";
2
  import { refreshOverlay, trackActiveElement, transitionStage } from "./overlay";
3
+ import { getConfig, getCurrentDriver } from "./config";
4
  import { hidePopover, renderPopover, repositionPopover } from "./popover";
5
  import { bringInView } from "./utils";
6
  import { getState, setState } from "./state";
 
71
  repositionPopover(activeHighlight, activeStep);
72
  }
73
 
 
74
  function transferHighlight(toElement: Element, toStep: DriveStep) {
75
  const duration = 400;
76
  const start = Date.now();
 
97
  deselectedHook(isFromDummyElement ? undefined : fromElement, fromStep!, {
98
  config,
99
  state,
100
+ driver: getCurrentDriver(),
101
  });
102
  }
103
 
 
105
  highlightStartedHook(isToDummyElement ? undefined : toElement, toStep, {
106
  config,
107
  state,
108
+ driver: getCurrentDriver(),
109
  });
110
  }
111
 
 
147
  highlightedHook(isToDummyElement ? undefined : toElement, toStep, {
148
  config: getConfig(),
149
  state: getState(),
150
+ driver: getCurrentDriver(),
151
  });
152
  }
153
 
src/popover.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { bringInView, getFocusableElements } from "./utils";
2
- import { Config, DriverHook, getConfig } from "./config";
3
- import { getState, setState, State } from "./state";
4
- import { DriveStep } from "./driver";
5
- import { onDriverClick } from "./events";
6
  import { emit } from "./emitter";
 
 
 
7
 
8
  export type Side = "top" | "right" | "bottom" | "left" | "over";
9
  export type Alignment = "start" | "center" | "end";
@@ -28,7 +28,7 @@ export type Popover = {
28
  prevBtnText?: string;
29
 
30
  // Called after the popover is rendered
31
- onPopoverRender?: (popover: PopoverDOM, opts: { config: Config; state: State }) => void;
32
 
33
  // Button callbacks
34
  onNextClick?: DriverHook;
@@ -168,6 +168,7 @@ export function renderPopover(element: Element, step: DriveStep) {
168
  return onNextClick(element, step, {
169
  config: getConfig(),
170
  state: getState(),
 
171
  });
172
  } else {
173
  return emit("nextClick");
@@ -179,6 +180,7 @@ export function renderPopover(element: Element, step: DriveStep) {
179
  return onPrevClick(element, step, {
180
  config: getConfig(),
181
  state: getState(),
 
182
  });
183
  } else {
184
  return emit("prevClick");
@@ -190,6 +192,7 @@ export function renderPopover(element: Element, step: DriveStep) {
190
  return onCloseClick(element, step, {
191
  config: getConfig(),
192
  state: getState(),
 
193
  });
194
  } else {
195
  return emit("closeClick");
@@ -204,7 +207,7 @@ export function renderPopover(element: Element, step: DriveStep) {
204
  return (
205
  !popover?.description.contains(target) &&
206
  !popover?.title.contains(target) &&
207
- typeof target.className === 'string' &&
208
  target.className.includes("driver-popover")
209
  );
210
  }
@@ -217,6 +220,7 @@ export function renderPopover(element: Element, step: DriveStep) {
217
  onPopoverRender(popover, {
218
  config: getConfig(),
219
  state: getState(),
 
220
  });
221
  }
222
 
@@ -581,7 +585,6 @@ function renderPopoverArrow(alignment: Alignment, side: Side, element: Element)
581
  arrowSide = "right";
582
  arrowAlignment = "end";
583
  }
584
- } else {
585
  }
586
 
587
  if (!arrowSide) {
@@ -589,6 +592,34 @@ function renderPopoverArrow(alignment: Alignment, side: Side, element: Element)
589
  } else {
590
  popoverArrow.classList.add(`driver-popover-arrow-side-${arrowSide}`);
591
  popoverArrow.classList.add(`driver-popover-arrow-align-${arrowAlignment}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  }
593
  }
594
 
 
1
+ import { Config, DriverHook, getConfig, getCurrentDriver } from "./config";
2
+ import { Driver, DriveStep } from "./driver";
 
 
 
3
  import { emit } from "./emitter";
4
+ import { onDriverClick } from "./events";
5
+ import { getState, setState, State } from "./state";
6
+ import { bringInView, getFocusableElements } from "./utils";
7
 
8
  export type Side = "top" | "right" | "bottom" | "left" | "over";
9
  export type Alignment = "start" | "center" | "end";
 
28
  prevBtnText?: string;
29
 
30
  // Called after the popover is rendered
31
+ onPopoverRender?: (popover: PopoverDOM, opts: { config: Config; state: State; driver: Driver }) => void;
32
 
33
  // Button callbacks
34
  onNextClick?: DriverHook;
 
168
  return onNextClick(element, step, {
169
  config: getConfig(),
170
  state: getState(),
171
+ driver: getCurrentDriver(),
172
  });
173
  } else {
174
  return emit("nextClick");
 
180
  return onPrevClick(element, step, {
181
  config: getConfig(),
182
  state: getState(),
183
+ driver: getCurrentDriver(),
184
  });
185
  } else {
186
  return emit("prevClick");
 
192
  return onCloseClick(element, step, {
193
  config: getConfig(),
194
  state: getState(),
195
+ driver: getCurrentDriver(),
196
  });
197
  } else {
198
  return emit("closeClick");
 
207
  return (
208
  !popover?.description.contains(target) &&
209
  !popover?.title.contains(target) &&
210
+ typeof target.className === "string" &&
211
  target.className.includes("driver-popover")
212
  );
213
  }
 
220
  onPopoverRender(popover, {
221
  config: getConfig(),
222
  state: getState(),
223
+ driver: getCurrentDriver(),
224
  });
225
  }
226
 
 
585
  arrowSide = "right";
586
  arrowAlignment = "end";
587
  }
 
588
  }
589
 
590
  if (!arrowSide) {
 
592
  } else {
593
  popoverArrow.classList.add(`driver-popover-arrow-side-${arrowSide}`);
594
  popoverArrow.classList.add(`driver-popover-arrow-align-${arrowAlignment}`);
595
+
596
+ const elementRect = element.getBoundingClientRect();
597
+ const arrowRect = popoverArrow.getBoundingClientRect();
598
+ const stagePadding = getConfig("stagePadding") || 0;
599
+
600
+ const isElementPartiallyInViewPort =
601
+ elementRect.left - stagePadding < window.innerWidth &&
602
+ elementRect.right + stagePadding > 0 &&
603
+ elementRect.top - stagePadding < window.innerHeight &&
604
+ elementRect.bottom + stagePadding > 0;
605
+
606
+ if (side === "bottom" && isElementPartiallyInViewPort) {
607
+ const isArrowWithinElementBounds =
608
+ arrowRect.x > elementRect.x && arrowRect.x + arrowRect.width < elementRect.x + elementRect.width;
609
+
610
+ if (!isArrowWithinElementBounds) {
611
+ popoverArrow.classList.remove(`driver-popover-arrow-align-${arrowAlignment}`);
612
+ popoverArrow.classList.add(`driver-popover-arrow-none`);
613
+ // reduce the top position by the padding
614
+ popover.wrapper.style.transform = `translateY(-${stagePadding / 2}px)`;
615
+ } else {
616
+ popover.wrapper.style.transform = `translateY(0)`;
617
+ }
618
+
619
+ // TODO: implement this using either of the following:
620
+ // 1 - move the arrow to the center of the element and point it towards the popover. This way, scrolling or resizing the window will move the arrow to the correct position.
621
+ // 2 - calculate the center position of the element and point the arrow towards the popover. However, we will have to re-calculate the position of the arrow when the window is resized or scrolled.
622
+ }
623
  }
624
  }
625
 
src/utils.ts CHANGED
@@ -30,12 +30,14 @@ export function bringInView(element: Element) {
30
 
31
  const shouldSmoothScroll = getConfig("smoothScroll");
32
 
 
 
33
  element.scrollIntoView({
34
  // Removing the smooth scrolling for elements which exist inside the scrollable parent
35
  // This was causing the highlight to not properly render
36
  behavior: !shouldSmoothScroll || hasScrollableParent(element) ? "auto" : "smooth",
37
  inline: "center",
38
- block: "center",
39
  });
40
  }
41
 
 
30
 
31
  const shouldSmoothScroll = getConfig("smoothScroll");
32
 
33
+ const isTallerThanViewport = (element as HTMLElement).offsetHeight > window.innerHeight;
34
+
35
  element.scrollIntoView({
36
  // Removing the smooth scrolling for elements which exist inside the scrollable parent
37
  // This was causing the highlight to not properly render
38
  behavior: !shouldSmoothScroll || hasScrollableParent(element) ? "auto" : "smooth",
39
  inline: "center",
40
+ block: isTallerThanViewport ? "start" : "center",
41
  });
42
  }
43