kamrify commited on
Commit
aa3b624
·
1 Parent(s): 4a0247e

Add basic highlight functionality

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
.babelrc DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/preset-env",
5
- {
6
- "corejs": "2",
7
- "useBuiltIns": "usage"
8
- }
9
- ]
10
- ],
11
- "plugins": [
12
- "@babel/plugin-proposal-object-rest-spread"
13
- ]
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.editorconfig DELETED
@@ -1,8 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = space
5
- indent_size = 2
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
 
 
 
 
 
 
 
 
 
.eslintignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ .history
2
+ .husky
3
+ .vscode
4
+ coverage
5
+ dist
6
+ node_modules
7
+ vite.config.ts
.eslintrc ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "root": true,
3
+ "parser": "@typescript-eslint/parser",
4
+ "plugins": ["@typescript-eslint", "prettier"],
5
+ "extends": [
6
+ "eslint:recommended",
7
+ "plugin:@typescript-eslint/eslint-recommended",
8
+ "plugin:@typescript-eslint/recommended",
9
+ "prettier"
10
+ ],
11
+ "env": {
12
+ "browser": true,
13
+ "node": true
14
+ },
15
+ "rules": {
16
+ "prettier/prettier": "error"
17
+ }
18
+ }
.eslintrc.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "extends": "airbnb-base",
3
- "env": {
4
- "browser": true
5
- },
6
- "rules": {
7
- "no-underscore-dangle": "off",
8
- "no-plusplus": "off",
9
- "no-cond-assign": "off",
10
- "func-names": "off",
11
- "no-continue": "off",
12
- "no-console": "off",
13
- "no-bitwise": "off",
14
- "class-methods-use-this": "off",
15
- "prefer-destructuring": "off",
16
- "no-param-reassign": [
17
- "off"
18
- ],
19
- "max-len": "off",
20
- "no-multi-spaces": "off"
21
- }
22
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore CHANGED
@@ -1,8 +1,26 @@
 
 
 
 
 
 
 
 
 
1
  node_modules
2
- npm-debug.log
3
- .DS_Store
 
 
 
 
 
 
 
4
  .idea
5
- .vscode
6
- package-lock.json
7
- yarn-error.log
8
- dist/demo
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
  node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+ coverage
15
+
16
+ # Editor directories and files
17
+ .vscode/*
18
+ .history/*
19
+ !.vscode/extensions.json
20
  .idea
21
+ .DS_Store
22
+ *.suo
23
+ *.ntvs*
24
+ *.njsproj
25
+ *.sln
26
+ *.sw?
.husky/pre-commit ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npx lint-staged
.lintstagedrc ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "./**/*.{ts,html,json}": "npm run format:scripts",
3
+ "./**/*.{css,scss}": "npm run format:styles"
4
+ }
.npmignore DELETED
@@ -1,8 +0,0 @@
1
- .editorconfig
2
- .idea
3
- .eslintrc.json
4
- index.html
5
- server.js
6
- demo
7
- config
8
- dist/demo
 
 
 
 
 
 
 
 
 
.prettierignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .history
2
+ .husky
3
+ .vscode
4
+ coverage
5
+ dist
6
+ node_modules
.prettierrc ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "printWidth": 80,
3
+ "tabWidth": 2,
4
+ "singleQuote": false,
5
+ "trailingComma": "es5",
6
+ "arrowParens": "avoid",
7
+ "bracketSpacing": true,
8
+ "useTabs": false,
9
+ "endOfLine": "auto",
10
+ "singleAttributePerLine": false,
11
+ "bracketSameLine": false,
12
+ "jsxBracketSameLine": false,
13
+ "jsxSingleQuote": false,
14
+ "quoteProps": "as-needed",
15
+ "semi": true
16
+ }
.stylelintignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ .history
2
+ .husky
3
+ .vscode
4
+ coverage
5
+ dist
6
+ node_modules
7
+ vite.config.ts
.stylelintrc ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "plugins": ["stylelint-prettier"],
3
+ "extends": [
4
+ "stylelint-config-recommended",
5
+ "stylelint-config-sass-guidelines",
6
+ "stylelint-config-prettier"
7
+ ],
8
+ "overrides": [
9
+ {
10
+ "files": ["**/*.scss"],
11
+ "customSyntax": "postcss-scss"
12
+ }
13
+ ],
14
+ "rules": {
15
+ "prettier/prettier": true,
16
+ "function-parentheses-space-inside": null,
17
+ "no-descending-specificity": null,
18
+ "max-nesting-depth": 2,
19
+ "selector-max-id": 1
20
+ }
21
+ }
config/webpack.config.demo.js DELETED
@@ -1,96 +0,0 @@
1
- const path = require('path');
2
- const CopyWebpackPlugin = require('copy-webpack-plugin');
3
- const ExtractTextPlugin = require('extract-text-webpack-plugin');
4
- const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
5
- const HtmlWebpackPlugin = require('html-webpack-plugin');
6
-
7
- const isProduction = process.env.NODE_ENV === 'production';
8
- const scriptFileName = 'driver-demo.min.js';
9
- const styleFileName = 'driver-demo.min.css';
10
-
11
- module.exports = {
12
- mode: isProduction ? 'production' : 'development',
13
- entry: [
14
- './demo/styles/demo.scss',
15
- './demo/scripts/demo.js',
16
- './src/index.js',
17
- ].filter(entryPoint => !!entryPoint),
18
- output: {
19
- path: path.join(__dirname, '/../dist/demo'),
20
- publicPath: './',
21
- filename: scriptFileName,
22
- libraryTarget: 'umd',
23
- library: 'Driver',
24
- libraryExport: 'default',
25
- },
26
- module: {
27
- rules: [
28
- {
29
- test: /\.js$/,
30
- exclude: /node_modules/,
31
- loader: 'eslint-loader',
32
- enforce: 'pre',
33
- options: {
34
- failOnWarning: false,
35
- failOnError: true,
36
- },
37
- },
38
- {
39
- test: /\.js$/,
40
- exclude: /node_modules/,
41
- loader: 'babel-loader',
42
- },
43
- {
44
- test: /.scss$/,
45
- loader: ExtractTextPlugin.extract([
46
- {
47
- loader: 'css-loader',
48
- options: { url: false },
49
- },
50
- {
51
- loader: 'postcss-loader',
52
- options: {
53
- ident: 'postcss',
54
- plugins: [require('autoprefixer')()], // eslint-disable-line global-require
55
- },
56
- },
57
- 'sass-loader',
58
- ]),
59
- },
60
- ],
61
- },
62
- plugins: [
63
- new ExtractTextPlugin({
64
- filename: styleFileName,
65
- allChunks: true,
66
- }),
67
- new OptimizeCssAssetsPlugin({
68
- assetNameRegExp: /\.min\.css$/g,
69
- // eslint-disable-next-line global-require
70
- cssProcessor: require('cssnano'),
71
- cssProcessorPluginOptions: {
72
- preset: [
73
- 'default',
74
- {
75
- discardComments: { removeAll: true },
76
- },
77
- ],
78
- },
79
- canPrint: true,
80
- }),
81
- new CopyWebpackPlugin([
82
- {
83
- from: './demo/images/',
84
- to: 'images',
85
- },
86
- ]),
87
- new HtmlWebpackPlugin({
88
- template: 'demo/index.html',
89
- favicon: 'demo/images/favicon.png',
90
- }),
91
- ],
92
- stats: {
93
- colors: true,
94
- },
95
- devtool: 'cheap-module-eval-source-map',
96
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/webpack.config.prod.js DELETED
@@ -1,79 +0,0 @@
1
- const path = require('path');
2
- const ExtractTextPlugin = require('extract-text-webpack-plugin');
3
- const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
4
-
5
- module.exports = {
6
- mode: 'production',
7
- entry: [
8
- './src/driver.scss',
9
- './src/index.js',
10
- ],
11
- output: {
12
- path: path.join(__dirname, '/../dist'),
13
- publicPath: '/dist/',
14
- filename: 'driver.min.js',
15
- libraryTarget: 'umd',
16
- library: 'Driver',
17
- libraryExport: 'default',
18
- },
19
- module: {
20
- rules: [
21
- {
22
- test: /\.js$/,
23
- exclude: /node_modules/,
24
- loader: 'eslint-loader',
25
- enforce: 'pre',
26
- options: {
27
- failOnWarning: false,
28
- failOnError: true,
29
- },
30
- },
31
- {
32
- test: /\.js$/,
33
- exclude: /node_modules/,
34
- loader: 'babel-loader',
35
- },
36
- {
37
- test: /.scss$/,
38
- loader: ExtractTextPlugin.extract([
39
- {
40
- loader: 'css-loader',
41
- options: { url: false },
42
- },
43
- {
44
- loader: 'postcss-loader',
45
- options: {
46
- ident: 'postcss',
47
- plugins: [require('autoprefixer')()], // eslint-disable-line global-require
48
- },
49
- },
50
- 'sass-loader',
51
- ]),
52
- },
53
- ],
54
- },
55
- plugins: [
56
- new ExtractTextPlugin({
57
- filename: 'driver.min.css',
58
- allChunks: true,
59
- }),
60
- new OptimizeCssAssetsPlugin({
61
- assetNameRegExp: /\.min\.css$/g,
62
- // eslint-disable-next-line global-require
63
- cssProcessor: require('cssnano'),
64
- cssProcessorPluginOptions: {
65
- preset: [
66
- 'default',
67
- {
68
- discardComments: { removeAll: true },
69
- },
70
- ],
71
- },
72
- canPrint: true,
73
- }),
74
- ],
75
- stats: {
76
- colors: true,
77
- },
78
- devtool: 'cheap-module-source-map',
79
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo/images/browserstack.png DELETED
Binary file (5.07 kB)
 
demo/images/driver.png DELETED
Binary file (46.1 kB)
 
demo/images/driver.svg DELETED
demo/images/favicon.png DELETED
Binary file (839 Bytes)
 
demo/images/separator.png DELETED
Binary file (6.88 kB)
 
demo/images/split.png DELETED
Binary file (439 Bytes)
 
demo/index.html DELETED
@@ -1,412 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport"
6
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
7
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
8
- <title>Driver</title>
9
- <meta name="description" itemprop="description" content="A light-weight, no-dependency, vanilla JavaScript library to drive the user's focus across the page"/>
10
- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai.min.css">
11
- </head>
12
- <body>
13
- <div class="page-wrap">
14
- <section class="section__header" id="driver-demo-head">
15
- <h1 class="brand">
16
- <img id="logo_img" src="./images/driver.png"/>
17
- <span id="name_driver">Driver.js</span>
18
- </h1>
19
- <p class="text-muted tagline">Light-weight, no-dependency, vanilla JavaScript engine to drive user's focus across
20
- the
21
- page</p>
22
-
23
- <a id="animated-tour" href="javascript:void(0)" class="btn btn__example btn__dark">With Animation</a>
24
- <a id="boring-tour" href="javascript:void(0)" class="btn btn__example btn__dark">Without Animation</a>
25
-
26
- <div class="github-button top-30">
27
- <!-- Place this tag where you want the button to render. -->
28
- <a class="github-button" href="https://github.com/kamranahmedse/driver.js" data-size="large"
29
- data-show-count="true" aria-label="Star kamranahmedse/driver.js on GitHub">Star</a>
30
- </div>
31
-
32
- </section>
33
-
34
- <blockquote>
35
- <p>A lightweight (~4kb gzipped) yet powerful JavaScript engine that helps you drive the user's focus on page.</p>
36
- <p class="zero-bottom">Some sample use-cases can be creating powerful feature introductions, call-to-action
37
- components, focus shifters etc.</p>
38
- </blockquote>
39
-
40
- <section class="section__purpose">
41
- <h3>What are the features?</h3>
42
- <p>Driver is compatible with all the major browsers and can be used for any of your overlay needs. Feature
43
- introductions, focus shifters, call-to-action are just a few examples.</p>
44
- <ul>
45
- <li id="highlight_feature">🔆 <strong>Highlight</strong> any (literally any) item on page</li>
46
- <li id="interactions_feature">✋ <strong>Block user interactions</strong></li>
47
- <li id="feature_introductions_feature">📣 Create <strong>feature introductions</strong></li>
48
- <li id="focus_shifters_feature">👓 Add <strong>focus shifters</strong> for users</li>
49
- <li id="customizable_feature">🛠️ Highly customizable – <strong>Use it anywhere</strong> for overlay</li>
50
- <li id="keyboard_feature">⌨️ User Friendly – <strong>Controllable by keys</strong></li>
51
- <li id="free_use_feature">🆓 <strong>MIT Licensed</strong> – Free for personal and commercial use</li>
52
- <li id="lightweight_feature">🕊️ Lightweight – Only <strong>~4kb</strong> when gzipped</li>
53
- <li id="major_browsers_feature">🌀 <strong>Consistent behavior</strong> across all major browsers</li>
54
- </ul>
55
- </section>
56
- <hr class="hr__fancy">
57
- <section class="section__how">
58
- <h3>How does it do that?</h3>
59
- <p>In it simplest, it puts the canvas on top of the whole page and then cuts the part that is over the element to be
60
- highlighted and provides you several hooks when highlighting, highlighted or un-highlighting elements making it
61
- highly customizable.</p>
62
- </section>
63
- <hr class="hr__fancy">
64
- <section class="section__examples">
65
- <div id="examples_section">
66
- <h3>Can you show some Examples?</h3>
67
- <p>Below you find some of the examples and sample use-cases on how you can use it.</p>
68
- </div>
69
- <div id="single-element-no-popover" class="section__example">
70
- <h4>Highlighting a Single Element – Without Popover</h4>
71
- <p class="zero-bottom">If all you want is just highlight a single element, you can do that simply by passing the
72
- selector</p>
73
- <a href="#" class="btn__run-demo" id="run-single-element-no-popover">Show Demo</a>
74
- <pre><code class="javascript">const driver = new Driver();
75
- driver.highlight('#create-post');
76
- </code></pre>
77
- </div>
78
-
79
- <hr class="hr__fancy">
80
-
81
- <div class="section__example">
82
- <p>A <strong>real world use-case</strong> for this could be highlighting an element when user is interacting with
83
- it</p>
84
- <pre><code class="javascript">const focusDriver = new Driver();
85
-
86
- // Highlight the section on focus
87
- document.getElementById('creation-input')
88
- .addEventListener('focus', (e) => {
89
- focusDriver.focus('#creation-input');
90
- });
91
- </code></pre>
92
- <p class="top-20">Focus any of the inputs and see how it moves the highlight from one element to the other</p>
93
- <div id="creation-forms">
94
- <input type="text" id="creation-input" class="form-control" placeholder="Focus any of the inputs">
95
- <input type="text" id="creation-input-2" class="form-control" placeholder="Focus any of the inputs">
96
- <input type="text" id="creation-input-3" class="form-control" placeholder="Focus any of the inputs">
97
- <input type="text" id="creation-input-4" class="form-control" placeholder="Focus any of the inputs">
98
- </div>
99
- </div>
100
-
101
- <p>You can also turn off the animation or set the padding around the corner. More on it later.</p>
102
-
103
- <hr class="hr__fancy">
104
-
105
- <div id="single-element-with-popover" class="section__example">
106
- <h4>Highlighting a Single Element – With Popover</h4>
107
- <p>If you would like to show some details alongside the highlighted element, you can do that easily by specifying
108
- title and description</p>
109
- <a href="#" class="btn__run-demo" id="run-single-element-with-popover">Show Demo</a>
110
- <pre><code class="javascript">const driver = new Driver();
111
- driver.highlight({
112
- element: '#some-element',
113
- popover: {
114
- title: 'Title for the Popover',
115
- description: 'Description for it',
116
- }
117
- });
118
- </code></pre>
119
- <p class="top-20">You can modify the behavior of this popover also by a certain set of options. More on it
120
- below.</p>
121
- </div>
122
-
123
- <hr class="hr__fancy">
124
-
125
- <div id="single-element-with-popover-position" class="section__example">
126
- <h4>Popover Positioning</h4>
127
- <p>You can also, change the position of the popover to be either <code>left</code>, <code>left-center</code>, <code>left-bottom</code>, <code>top</code>, <code>top-center</code>, <code>top-right</code>,
128
- <code>right</code>, <code>right-center</code>, <code>right-bottom</code> or <code>bottom</code>, <code>bottom-center</code>, <code>bottom-right</code>, <code>mid-center</code>.</p>
129
- <a href="#" class="btn__run-demo" id="run-single-element-with-popover-position">Show Demo</a>
130
- <pre><code class="javascript">const driver = new Driver();
131
- driver.highlight({
132
- element: '#some-element',
133
- popover: {
134
- title: 'Title for the Popover',
135
- description: 'Description for it',
136
- // position can be left, left-center, left-bottom, top,
137
- // top-center, top-right, right, right-center, right-bottom,
138
- // bottom, bottom-center, bottom-right, mid-center
139
- position: 'left',
140
- }
141
- });
142
- </code></pre>
143
- </div>
144
- <div class="section__example">
145
- <div class="top-90 position-btns" id="position-btns">
146
- <a href="#" id="position-btn-left" data-alignment="left">Left, Left Top</a>
147
- <a href="#" id="position-btn-left-center" data-alignment="left-center">Left Center</a>
148
- <a href="#" id="position-btn-left-bottom" data-alignment="left-bottom">Left Bottom</a>
149
-
150
- <a href="#" id="position-btn-right" data-alignment="right">Right, Right Top</a>
151
- <a href="#" id="position-btn-right-center" data-alignment="right-center">Right Center</a>
152
- <a href="#" id="position-btn-right-bottom" data-alignment="right-bottom">Right Bottom</a>
153
-
154
- <a href="#" id="position-btn-top" data-alignment="top">Top, Top-left</a>
155
- <a href="#" id="position-btn-top-center" data-alignment="top-center">Top Center</a>
156
- <a href="#" id="position-btn-top-right" data-alignment="top-right">Top Right</a>
157
-
158
- <a href="#" id="position-btn-bottom" data-alignment="bottom">Bottom, Bottom left</a>
159
- <a href="#" id="position-btn-bottom-center" data-alignment="bottom-center">Bottom center</a>
160
- <a href="#" id="position-btn-bottom-right" data-alignment="bottom-right">Bottom right</a>
161
-
162
- <a href="#" id="position-btn-mid-center" data-alignment="mid-center">Mid Center</a>
163
- <!-- <a href="#" id="position-btn-auto" data-alignment="auto">Auto</a> -->
164
- </div>
165
- <p class="top-20">If you don't specify the position or specify it to be <code>auto</code>, it will automatically
166
- find the suitable position for the popover and show it</p>
167
- </div>
168
- <hr class="hr__fancy">
169
- <div id="single-element-with-popover-html" class="section__example">
170
- <h4>HTML in Popovers</h4>
171
- <p>You can also specify HTML in the body or the title of the popovers. Here is an example:</p>
172
- <a href="#" class="btn__run-demo" id="run-single-element-with-popover-html">Show Demo</a>
173
- <pre><code class="javascript">const driver = new Driver();
174
- driver.highlight({
175
- element: '#some-element',
176
- popover: {
177
- title: '&lt;em&gt;An italicized title&lt;/em&gt;',
178
- description: 'Description may also contain &lt;strong&gt;HTML&lt;/strong&gt;'
179
- }
180
- });
181
- </code></pre>
182
- </div>
183
-
184
- <p class="top-20">And of course it can be any valid HTML.</p>
185
-
186
- <hr class="hr__fancy">
187
- <div id="single-element-no-close" class="section__example">
188
- <h4>Disable Close on Outside Click</h4>
189
- <p>By default, driver.js gets reset if user clicks outside the highlighted element, you can disable this:</p>
190
- <a href="#" class="btn__run-demo" id="run-single-element-no-close">Show Demo</a>
191
- <pre><code class="javascript">const driver = new Driver({
192
- allowClose: false,
193
- });
194
-
195
- driver.highlight({
196
- element: '#some-element',
197
- popover: {
198
- title: '&lt;em&gt;An italicized title&lt;/em&gt;',
199
- description: 'Description may also contain &lt;strong&gt;HTML&lt;/strong&gt;'
200
- }
201
- });
202
- </code></pre>
203
- <p class="top-20">
204
- If you use this option, for multi-step driver, it would close after you are done with the popover or you can close it programmatically. For single element popover, you need to close it properly, otherwise it won't be closed
205
- </p>
206
- <pre><code class="javascript">driver.reset()</code>
207
- </div>
208
-
209
- <hr class="hr__fancy">
210
- <div id="third-element-introduction" class="section__example">
211
- <h4 id="first-element-introduction">Creating Feature Introductions</h4>
212
- <p id="second-para-feature-introductions">You can also make powerful feature introductions to guide the users
213
- about the features. Just provide an array of steps where each step specifies an element to highlight.</p>
214
- <p id="third-para-feature-introductions">Below is just a quick example showing you how to combine the steps in
215
- introduction.</p>
216
- <a href="#" class="btn__run-demo" id="run-multi-element-popovers">Show Demo</a>
217
- </div>
218
- <pre><code class="javascript">const driver = new Driver();
219
- // Define the steps for introduction
220
- driver.defineSteps([
221
- {
222
- element: '#first-element-introduction',
223
- popover: {
224
- className: 'first-step-popover-class',
225
- title: 'Title on Popover',
226
- description: 'Body of the popover',
227
- position: 'left'
228
- }
229
- },
230
- {
231
- element: '#second-element-introduction',
232
- popover: {
233
- title: 'Title on Popover',
234
- description: 'Body of the popover',
235
- position: 'top'
236
- }
237
- },
238
- {
239
- element: '#third-element-introduction',
240
- popover: {
241
- title: 'Title on Popover',
242
- description: 'Body of the popover',
243
- position: 'right'
244
- }
245
- },
246
- ]);
247
- // Start the introduction
248
- driver.start();
249
- </code></pre>
250
- <p class="top-20">This is just a quick example for the feature introduction. For a richer one, please have a look at
251
- the
252
- <a href="#" class="btn__example">"Quick Tour"</a></p>
253
-
254
- <p>You may also turn off the footer buttons in popover, in which case user can control the popover using the arrows
255
- keys on keyboard. Or you may control it using the methods provided by Driver.</p>
256
-
257
- <hr class="hr__fancy">
258
-
259
- <div id="element-without-popover" class="section__example">
260
- <h4>Without Overlay</h4>
261
- <p>You can create feature introductions and do everything listed above without overlays also. All you have to do
262
- is just set the opacity to `0`.</p>
263
- <a href="#" class="btn__run-demo" id="run-element-without-popover">Show Demo</a>
264
- <pre><code class="javascript">const driver = new Driver({
265
- opacity: 0,
266
- });
267
-
268
- driver.highlight({
269
- element: '#run-element-without-popover',
270
- popover: {
271
- title: 'Title for the Popover',
272
- description: 'Description for it',
273
- position: 'top', // can be `top`, `left`, `right`, `bottom`
274
- }
275
- });
276
- </code></pre>
277
- <p class="top-20">..and you can do the same for the feature introductions</p>
278
- </div>
279
-
280
- <hr class="hr__fancy">
281
-
282
- <div class="section__example">
283
- <div id="api_section">
284
- <h3>..and much much more</h3>
285
- <p>Driver comes with many options that you can manipulate to make driver behave as you may like</p>
286
- </div>
287
- <h4>Driver Definition</h4>
288
- <p>Here are the options that Driver understands</p>
289
- <pre><code class="javascript">const driver = new Driver({
290
- className: 'scoped-class', // className to wrap driver.js popover
291
- animate: true, // Animate while changing highlighted element
292
- opacity: 0.75, // Background opacity (0 means only popovers and without overlay)
293
- padding: 10, // Distance of element from around the edges
294
- allowClose: true, // Whether clicking on overlay should close or not
295
- overlayClickNext: false, // Should it move to next step on overlay click
296
- doneBtnText: 'Done', // Text on the final button
297
- closeBtnText: 'Close', // Text on the close button for this step
298
- nextBtnText: 'Next', // Next button text for this step
299
- prevBtnText: 'Previous', // Previous button text for this step
300
- showButtons: false, // Do not show control buttons in footer
301
- keyboardControl: true, // Allow controlling through keyboard (escape to close, arrow keys to move)
302
- scrollIntoViewOptions: {}, // We use `scrollIntoView()` when possible, pass here the options for it if you want any
303
- onHighlightStarted: (Element) {}, // Called when element is about to be highlighted
304
- onHighlighted: (Element) {}, // Called when element is fully highlighted
305
- onDeselected: (Element) {}, // Called when element has been deselected
306
- onReset: (Element) {}, // Called when overlay is about to be cleared
307
- onNext: (Element) => {}, // Called when moving to next step on any step
308
- onPrevious: (Element) => {}, // Called when moving to next step on any step
309
- });
310
- </code></pre>
311
- </div>
312
- <p class="top-20">Note that all the button options that you provide in the driver definition can be overridden for a
313
- specific step by giving them in the step definition</p>
314
- <div class="section__example">
315
- <h4>Step Definition</h4>
316
- <p>Here are the set of options that you can pass in each step i.e. an item in array of steps or the object that
317
- you pass to <code>highlight</code> method</p>
318
- <pre><code class="javascript">const stepDefinition = {
319
- element: '#some-item', // Query selector string or Node to be highlighted
320
- popover: { // There will be no popover if empty or not given
321
- className: 'popover-class', // className to wrap this specific step popover in addition to the general className in Driver options
322
- title: 'Title', // Title on the popover
323
- description: 'Description', // Body of the popover
324
- showButtons: false, // Do not show control buttons in footer
325
- closeBtnText: 'Close', // Text on the close button for this step
326
- nextBtnText: 'Next', // Next button text for this step
327
- prevBtnText: 'Previous', // Previous button text for this step
328
- }
329
- };
330
- </code></pre>
331
- </div>
332
- <div class="section__example">
333
- <h4>API Methods</h4>
334
- <p>Below are the set of methods that are available to you</p>
335
- <pre><code class="javascript">const driver = new Driver(driverOptions);
336
-
337
- const isActivated = driver.isActivated; // Checks if the driver is active or not
338
- driver.moveNext(); // Moves to next step in the steps list
339
- driver.movePrevious(); // Moves to previous step in the steps list
340
- driver.start(stepNumber = 0); // Starts driving through the defined steps
341
- driver.highlight(string|stepDefinition); // highlights the element using query selector or the step definition
342
- driver.reset(); // Resets the overlay and clears the screen
343
- driver.hasHighlightedElement(); // Checks if there is any highlighted element
344
- driver.hasNextStep(); // Checks if there is next step to move to
345
- driver.hasPreviousStep(); // Checks if there is previous step to move to
346
-
347
- // Prevents the current move. Useful in `onNext` or `onPrevious` if you want to
348
- // perform some asynchronous task and manually move to next step
349
- driver.preventMove();
350
-
351
- // Gets the currently highlighted element on screen
352
- const activeElement = driver.getHighlightedElement();
353
- const lastActiveElement = driver.getLastHighlightedElement();
354
- activeElement.getCalculatedPosition(); // Gets screen co-ordinates of the active element
355
- activeElement.hidePopover(); // Hide the popover
356
- activeElement.showPopover(); // Show the popover
357
-
358
- activeElement.getNode(); // Gets the DOM Element behind this element
359
- </code></pre>
360
- </div>
361
- <p class="top-20">You can use a variety of options to achieve whatever you may want. I have some plans on improving
362
- it further, make sure to keep an eye on the <a href="https://github.com/kamranahmedse/driver.js" target="_blank">GitHub
363
- page</a></p>
364
- </section>
365
- <hr class="hr__fancy">
366
- <div class="section__example">
367
- <h4>Contributing</h4>
368
- <p>You can find the contribution instructions on the <a href="https://github.com/kamranahmedse/driver.js"
369
- target="_blank">GitHub page</a>. Feel free to submit an
370
- issue, create a pull request or spread the word</p>
371
- </div>
372
- <hr class="hr__fancy">
373
- <div class="section__example">
374
- <p>A product by <a href="http://twitter.com/kamranahmedse" target="_blank">Kamran</a> produced out of boredom and
375
- frustration after he gave up on trying to find a perfect solution to integrate journey introduction
376
- and overlays.</p>
377
- <a href="https://twitter.com/kamranahmedse?ref_src=twsrc%5Etfw"
378
- class="twitter-follow-button mr-3"
379
- data-show-screen-name="false"
380
- data-size="large"
381
- target="_blank"
382
- data-show-count="true">Follow @kamranahmedse</a>
383
-
384
- <a class="github-button" href="https://github.com/kamranahmedse"
385
- data-size="large"
386
- target="_blank"
387
- data-show-count="true"
388
- aria-label="Follow @kamranahmedse on GitHub">Follow</a>
389
- </div>
390
- </div>
391
-
392
- <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
393
- <script async defer src="//buttons.github.io/buttons.js"></script>
394
- <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
395
-
396
- <script>
397
- (function (i, s, o, g, r, a, m) {
398
- i['GoogleAnalyticsObject'] = r;
399
- i[r] = i[r] || function () {
400
- (i[r].q = i[r].q || []).push(arguments);
401
- }, i[r].l = 1 * new Date();
402
- a = s.createElement(o),
403
- m = s.getElementsByTagName(o)[0];
404
- a.async = 1;
405
- a.src = g;
406
- m.parentNode.insertBefore(a, m);
407
- })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
408
- ga('create', 'UA-58155965-1', 'auto');
409
- ga('send', 'pageview');
410
- </script>
411
- </body>
412
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo/scripts/demo.js DELETED
@@ -1,359 +0,0 @@
1
- /* eslint-disable */
2
- import Driver from '../../src';
3
-
4
- document.addEventListener('DOMContentLoaded', function () {
5
- const tourSteps = [
6
- {
7
- element: document.getElementById('driver-demo-head'),
8
- popover: {
9
- className: 'scoped-driver-popover',
10
- title: 'Before we start',
11
- description: 'This is just one use-case, make sure to check out the rest of the docs below.',
12
- nextBtnText: 'Okay, Start!',
13
- },
14
- }, {
15
- element: '#logo_img',
16
- popover: {
17
- title: 'Focus Anything',
18
- description: 'You can use it to highlight literally anything, images, text, div, span, li etc.',
19
- },
20
- }, {
21
- element: '#name_driver',
22
- popover: {
23
- title: 'Why Driver?',
24
- description: 'Because it lets you drive the user across the page',
25
- }
26
- }, {
27
- element: '#driver-demo-head',
28
- popover: {
29
- title: 'Let\'s talk features',
30
- description: 'You may leave your mouse and use the <strong>arrow keys</strong> to move next and back or <strong>escape key</strong> anytime to close this',
31
- position: 'bottom'
32
- }
33
- }, {
34
- element: '#highlight_feature',
35
- popover: {
36
- title: 'Highlight Feature',
37
- description: 'You may use it to highlight single elements (with or without popover) e.g. like facebook does while creating posts',
38
- }
39
- }, {
40
- element: '#feature_introductions_feature',
41
- popover: {
42
- title: 'Feature Introductions',
43
- description: 'With it\'s powerful API you can use it to make programmatic or user driven feature introductions',
44
- position: 'bottom'
45
- }
46
- }, {
47
- element: '#focus_shifters_feature',
48
- popover: {
49
- title: 'Focus Shifters',
50
- description: 'If some element or part of the page needs user\'s interaction, you can just call the highlight method. Driver will take care of driving the user there',
51
- position: 'bottom'
52
- }
53
- }, {
54
- element: '#customizable_feature',
55
- popover: {
56
- title: 'Highly Customizable',
57
- description: 'Driver has a powerful API allowing you to customize the experience as much as you can.',
58
- position: 'bottom'
59
- }
60
- }, {
61
- element: '#keyboard_feature',
62
- popover: {
63
- title: 'User Friendly',
64
- description: 'Your users can control it with the arrow keys on keyboard, or escape to close it',
65
- position: 'bottom'
66
- }
67
- }, {
68
- element: '#free_use_feature',
69
- popover: {
70
- title: 'MIT License',
71
- description: 'I believe in open-source and thus Driver is completely free for both personal or commercial use'
72
- }
73
- }, {
74
- element: '#lightweight_feature',
75
- popover: {
76
- title: 'Only ~4KB',
77
- description: 'Driver is free of bloat and written in Vanilla JS. There is no external dependency at all, thus keeping it smaller in size.'
78
- }
79
- }, {
80
- element: '#examples_section',
81
- popover: {
82
- title: 'Usage Examples',
83
- description: 'Have a look at the usage examples and see how you can use it.'
84
- }
85
- }, {
86
- element: '#driver-demo-head',
87
- popover: {
88
- title: 'Quick Tour Ends',
89
- description: 'This was just a sneak peak, have a look at the API section and examples to learn more!'
90
- }
91
- }
92
- ];
93
-
94
- const animatedTourDriver = new Driver({
95
- animate: true,
96
- opacity: 0.8,
97
- padding: 5,
98
- showButtons: true,
99
- });
100
-
101
- const boringTourDriver = new Driver({
102
- animate: false,
103
- opacity: 0.8,
104
- padding: 5,
105
- showButtons: true,
106
- className: 'boring-scope',
107
- });
108
-
109
- boringTourDriver.defineSteps(tourSteps);
110
- animatedTourDriver.defineSteps(tourSteps);
111
-
112
- document.querySelector('#animated-tour')
113
- .addEventListener('click', () => {
114
- if (boringTourDriver.isActivated) {
115
- boringTourDriver.reset(true);
116
- }
117
-
118
- animatedTourDriver.start();
119
- });
120
-
121
- document.querySelector('#boring-tour')
122
- .addEventListener('click', () => {
123
- if (animatedTourDriver.isActivated) {
124
- animatedTourDriver.reset(true);
125
- }
126
-
127
- boringTourDriver.start();
128
- });
129
-
130
-
131
- try {
132
- document.querySelectorAll('pre code')
133
- .forEach((element) => {
134
- hljs.highlightBlock(element);
135
- });
136
- } catch (e) {
137
- // Silently ignore the highlight errors
138
- }
139
-
140
-
141
- /////////////////////////////////////////////
142
- // First example – highlighting without popover
143
- /////////////////////////////////////////////
144
- const singleDriverNoPopover = new Driver();
145
- document.querySelector('#run-single-element-no-popover')
146
- .addEventListener('click', (e) => {
147
- e.preventDefault();
148
- singleDriverNoPopover.highlight('#single-element-no-popover');
149
- });
150
-
151
- /////////////////////////////////////////////
152
- // Form focus examples
153
- /////////////////////////////////////////////
154
- const focusDriver = new Driver({ padding: 0 });
155
- const inputIds = ['creation-input', 'creation-input-2', 'creation-input-3', 'creation-input-4'];
156
- inputIds.forEach(inputId => {
157
- // Highlight the section on focus
158
- document.getElementById(inputId)
159
- .addEventListener('focus', () => {
160
- focusDriver.highlight(`#${inputId}`);
161
- });
162
- });
163
-
164
- /////////////////////////////////////////////
165
- // Highlighting single element with popover
166
- /////////////////////////////////////////////
167
- const singleDriverWithPopover = new Driver();
168
- document.querySelector('#run-single-element-with-popover')
169
- .addEventListener('click', (e) => {
170
- e.preventDefault();
171
- singleDriverWithPopover.highlight({
172
- element: '#single-element-with-popover',
173
- showButtons: false,
174
- popover: {
175
- title: 'Did you know?',
176
- description: 'You can add HTML in title or description also!',
177
- position: 'top'
178
- }
179
- });
180
- });
181
-
182
- /////////////////////////////////////////////////////
183
- // Highlighting single element with popover position
184
- /////////////////////////////////////////////////////
185
- const singleDriverWithPopoverPosition = new Driver();
186
- document.querySelector('#run-single-element-with-popover-position')
187
- .addEventListener('click', (e) => {
188
- e.preventDefault();
189
-
190
- singleDriverWithPopoverPosition.highlight({
191
- element: '#single-element-with-popover-position',
192
- showButtons: false,
193
- popover: {
194
- title: 'Did you know?',
195
- description: 'You can add HTML in title or description also!',
196
- position: 'top'
197
- }
198
- });
199
- });
200
-
201
- /////////////////////////////////////////////////////
202
- // Highlighting single element with popover position
203
- /////////////////////////////////////////////////////
204
- const positionBtnsDriver = new Driver({
205
- padding: 0,
206
- });
207
-
208
- document.querySelector('#position-btns')
209
- .addEventListener('click', (e) => {
210
- e.preventDefault();
211
-
212
- let id = e.target.id;
213
- let alignment = e.target.dataset.alignment;
214
-
215
- if (!alignment) return;
216
-
217
- positionBtnsDriver.highlight({
218
- element: `#${id}`,
219
- showButtons: false,
220
- popover: {
221
- title: 'Did you know?',
222
- description: 'You can add HTML in title or description also!',
223
- position: alignment
224
- }
225
- });
226
- })
227
-
228
- /////////////////////////////////////////////////////
229
- // Highlighting single element with popover position
230
- /////////////////////////////////////////////////////
231
- const htmlDriver = new Driver();
232
-
233
- document.querySelector('#run-single-element-with-popover-html')
234
- .addEventListener('click', (e) => {
235
- e.preventDefault();
236
-
237
- htmlDriver.highlight({
238
- element: '#single-element-with-popover-html',
239
- showButtons: false,
240
- popover: {
241
- title: '<em>Tags</em> in title or <u>body</u>',
242
- description: 'Body can also have <strong>html tags</strong>!',
243
- position: 'top'
244
- }
245
- });
246
- });
247
-
248
- /////////////////////////////////////////////////////
249
- // Without Overlay Example
250
- /////////////////////////////////////////////////////
251
- const withoutOverlay = new Driver({
252
- opacity: 0,
253
- padding: 0
254
- });
255
-
256
- document.querySelector('#run-element-without-popover')
257
- .addEventListener('click', (e) => {
258
- e.preventDefault();
259
-
260
- withoutOverlay.highlight({
261
- element: '#run-element-without-popover',
262
- popover: {
263
- title: 'Title for the Popover',
264
- description: 'Description for it',
265
- position: 'top', // can be `top`, `left`, `right`, `bottom`
266
- }
267
- });
268
- });
269
-
270
- /////////////////////////////////////////////
271
- // Single no close demo
272
- /////////////////////////////////////////////
273
- const singleNoClose = new Driver({
274
- allowClose: false,
275
- position: 'top'
276
- });
277
-
278
- singleNoClose.defineSteps([{
279
- element: '#single-element-no-close',
280
- popover: {
281
- title: 'Uh-huh!',
282
- description: 'You cannot close by clicking outside'
283
- }
284
- }, {
285
- element: '#third-element-introduction',
286
- popover: {
287
- title: 'Title on Popover',
288
- description: 'Body of the popover',
289
- position: 'top'
290
- }
291
- }]);
292
-
293
- document.querySelector('#run-single-element-no-close')
294
- .addEventListener('click', function (e) {
295
- e.preventDefault();
296
- singleNoClose.start();
297
- });
298
-
299
- /////////////////////////////////////////////////////
300
- // Highlighting single element with popover position
301
- /////////////////////////////////////////////////////
302
- const featureIntroductionDriver = new Driver();
303
- featureIntroductionDriver.defineSteps([
304
- {
305
- element: '#first-element-introduction',
306
- popover: {
307
- className: 'first-step-popover-class',
308
- title: 'Title on Popover',
309
- description: 'Body of the popover',
310
- position: 'top'
311
- }
312
- },
313
- {
314
- element: '#second-para-feature-introductions',
315
- popover: {
316
- title: 'Title on Popover',
317
- description: 'Body of the popover',
318
- position: 'bottom'
319
- }
320
- },
321
- {
322
- element: '#third-para-feature-introductions',
323
- popover: {
324
- title: 'Title on Popover',
325
- description: 'Body of the popover',
326
- position: 'top'
327
- }
328
- },
329
- {
330
- element: '#run-multi-element-popovers',
331
- popover: {
332
- title: 'Title on Popover',
333
- description: 'Body of the popover',
334
- position: 'top'
335
- }
336
- },
337
- {
338
- element: '#third-element-introduction',
339
- popover: {
340
- title: 'Title on Popover',
341
- description: 'Body of the popover',
342
- position: 'top'
343
- }
344
- },
345
- ]);
346
-
347
- document.querySelector('#run-multi-element-popovers')
348
- .addEventListener('click', (e) => {
349
- e.preventDefault();
350
- e.stopPropagation();
351
- featureIntroductionDriver.start();
352
- });
353
-
354
- const newURL = location.href.split('?')[0];
355
- if (newURL !== location.href) {
356
- window.location = newURL;
357
- window.location.href = newURL;
358
- }
359
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo/styles/base.scss DELETED
@@ -1,154 +0,0 @@
1
- $global-guttering: 24px;
2
- $global-font-size-h1: 32px;
3
- $global-font-size-h2: 24px;
4
- $global-font-size-h3: 20px;
5
- $global-font-size-h4: 18px;
6
- $global-font-size-h5: 16px;
7
- $global-font-size-h6: 14px;
8
- $heading-font-weight: 700;
9
-
10
- /*=============================================
11
- = Generic styling =
12
- =============================================*/
13
-
14
- * {
15
- -webkit-font-smoothing: antialiased;
16
- -moz-osx-font-smoothing: grayscale;
17
- margin: 0;
18
- padding: 0;
19
- }
20
-
21
- *, *:before, *:after {
22
- box-sizing: border-box
23
- }
24
-
25
- html, body {
26
- position: relative;
27
- margin: 0;
28
- width: 100%;
29
- height: 100%;
30
- }
31
-
32
- body {
33
- padding-top: 1px;
34
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
35
- font-size: 16px;
36
- line-height: 1.4;
37
- color: white;
38
- background-color: #2E2E30;
39
- overflow-x: hidden;
40
- }
41
-
42
- label {
43
- display: block;
44
- margin-bottom: 8px;
45
- font-size: 14px;
46
- font-weight: 500;
47
- cursor: pointer;
48
- }
49
-
50
- p {
51
- margin-top: 0;
52
- margin-bottom: 20px;
53
- line-height: 1.5;
54
- }
55
-
56
- hr, .hr {
57
- display: block;
58
- margin: $global-guttering*1.25 0;
59
- border: 0;
60
- border-bottom: 1px solid #eaeaea;
61
- height: 1px;
62
-
63
- &.hr__fancy {
64
- background: url("./images/separator.png") repeat-y;
65
- height: 5px;
66
- background-size: cover;
67
- }
68
- }
69
-
70
- h1, h2, h3, h4, h5, h6 {
71
- margin-top: 0;
72
- margin-bottom: $global-guttering/2;
73
- font-weight: $heading-font-weight;
74
- line-height: 1.2;
75
- }
76
-
77
- a, a:visited, a:focus {
78
- color: #FFFFFF;
79
- text-decoration: none;
80
- font-weight: 600;
81
- }
82
-
83
- .form-control {
84
- display: block;
85
- width: 100%;
86
- background-color: #f9f9f9;
87
- padding: 12px;
88
- border: 1px solid #ddd;
89
- border-radius: 2.5px;
90
- font-size: 14px;
91
- -webkit-appearance: none;
92
- appearance: none;
93
- outline: none;
94
- margin-bottom: $global-guttering;
95
- }
96
-
97
- h1, .h1 {
98
- font-size: $global-font-size-h1;
99
- }
100
-
101
- h2, .h2 {
102
- font-size: $global-font-size-h2;
103
- }
104
-
105
- h3, .h3 {
106
- font-size: $global-font-size-h3;
107
- }
108
-
109
- h4, .h4 {
110
- font-size: $global-font-size-h4;
111
- }
112
-
113
- h5, .h5 {
114
- font-size: $global-font-size-h5;
115
- }
116
-
117
- h6, .h6 {
118
- font-size: $global-font-size-h6;
119
- }
120
-
121
- ul li, ol li {
122
- list-style-type: none;
123
- line-height: 1.5;
124
- margin-bottom: 3px;
125
- }
126
-
127
- blockquote {
128
- background: #f5f3f1;
129
- padding: 10px;
130
- margin-bottom: 35px;
131
- border-radius: 10px;
132
- }
133
-
134
- .top-20 {
135
- margin-top: 20px;
136
- }
137
-
138
- .top-30 {
139
- margin-top: 30px;
140
- }
141
-
142
- .zero-bottom {
143
- margin-bottom: 0;
144
- }
145
-
146
- .zero-top {
147
- margin-top: 0;
148
- }
149
-
150
- .text-center {
151
- text-align: center;
152
- }
153
-
154
- /*===== End of Section comment block ======*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo/styles/demo.scss DELETED
@@ -1,129 +0,0 @@
1
- @import "./base";
2
- @import "../../src/driver";
3
-
4
- img.emoji {
5
- height: 1em;
6
- width: 1em;
7
- margin: 0 .05em 0 .1em;
8
- vertical-align: -0.1em;
9
- }
10
-
11
- .brand {
12
- position: relative;
13
-
14
- img {
15
- height: 67px;
16
- position: relative;
17
- top: 10px;
18
- }
19
- }
20
-
21
- .page-wrap {
22
- max-width: 550px;
23
- margin: 50px auto;
24
- background: white;
25
- padding: 10px 30px;
26
- border-radius: 5px;
27
- color: #1f1f1f;
28
-
29
- a, a:visited, a:focus {
30
- color: #1f1f1f;
31
- text-decoration: underline;
32
- }
33
-
34
- a.btn__dark {
35
- text-decoration: none;
36
- color: #FFFFFF;
37
- background-color: #F44336;
38
- padding: 0 18px;
39
- height: 40px;
40
- line-height: 40px;
41
- border-radius: 8px;
42
- cursor: pointer;
43
- transition: background-color 0.2s, color 0.2s;
44
- font-weight: 500;
45
- width: 195px;
46
- font-size: 17px;
47
- display: inline-block;
48
- margin-top: 2px;
49
- }
50
-
51
- a.btn__run-demo {
52
- text-decoration: none;
53
- background: #f54336;
54
- padding: 5px;
55
- border-radius: 20px;
56
- color: white;
57
- display: block;
58
- margin: 15px 0 10px;
59
- text-align: center;
60
- }
61
- }
62
-
63
- section {
64
- margin-bottom: $global-guttering*1.25;
65
- }
66
-
67
- .section__header {
68
- margin: 10px 0 20px;
69
- text-align: center;
70
- display: block;
71
- padding: 10px;
72
-
73
- h1 {
74
- font-size: 55px;
75
-
76
- .emoji {
77
- font-size: 45px;
78
- top: -4px;
79
- margin-right: 3px;
80
- position: relative;
81
- }
82
- }
83
-
84
- .tagline {
85
- max-width: 450px;
86
- margin: 0 auto 25px;
87
- text-align: center;
88
- }
89
- }
90
-
91
- .section__examples {
92
- .section__example {
93
- margin-bottom: 20px;
94
- }
95
-
96
- #creation-input {
97
- margin-top: 20px;
98
- }
99
-
100
- input {
101
- padding: 10px;
102
- background-color: #fafbfc;
103
- border: 3px solid #e1e4e8;
104
- border-radius: 3px;
105
- box-shadow: inset 0 0 10px rgba(27, 31, 35, 0.05);
106
- margin-bottom: 0;
107
- margin-top: 7px;
108
- }
109
- }
110
-
111
- .position-btns {
112
- display: grid;
113
- grid-template-columns: repeat(3,1fr);
114
- grid-gap: 8px;
115
- text-align: center;
116
-
117
- #position-btn-mid-center{
118
- grid-column: 2/ span 1;
119
- }
120
- }
121
-
122
- .position-btns a {
123
- text-decoration: none;
124
- font-size: 13px;
125
- padding: 10px 15px;
126
- background: #f54336;
127
- color: white !important;
128
- border-radius: 6px;
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dist/driver.min.css DELETED
@@ -1 +0,0 @@
1
- div#driver-popover-item{display:none;position:absolute;background:#fff;color:#2d2d2d;margin:0;padding:15px;border-radius:5px;min-width:250px;max-width:300px;box-shadow:0 1px 10px rgba(0,0,0,.4);z-index:1000000000}div#driver-popover-item .driver-popover-tip{border:5px solid #fff;content:"";position:absolute}div#driver-popover-item .driver-popover-tip.bottom{bottom:-10px;border-color:#fff transparent transparent}div#driver-popover-item .driver-popover-tip.bottom.position-center{left:49%}div#driver-popover-item .driver-popover-tip.bottom.position-right{right:20px}div#driver-popover-item .driver-popover-tip.left{left:-10px;top:10px;border-color:transparent #fff transparent transparent}div#driver-popover-item .driver-popover-tip.left.position-center{top:46%}div#driver-popover-item .driver-popover-tip.left.position-bottom{top:auto;bottom:20px}div#driver-popover-item .driver-popover-tip.right{right:-10px;top:10px;border-color:transparent transparent transparent #fff}div#driver-popover-item .driver-popover-tip.right.position-center{top:46%}div#driver-popover-item .driver-popover-tip.right.position-bottom{top:auto;bottom:20px}div#driver-popover-item .driver-popover-tip.top{top:-10px;border-color:transparent transparent #fff}div#driver-popover-item .driver-popover-tip.top.position-center{left:49%}div#driver-popover-item .driver-popover-tip.top.position-right{right:20px}div#driver-popover-item .driver-popover-tip.mid-center{display:none}div#driver-popover-item .driver-popover-footer{display:block;margin-top:10px}div#driver-popover-item .driver-popover-footer button{display:inline-block;padding:3px 10px;border:1px solid #d4d4d4;text-decoration:none;text-shadow:1px 1px 0 #fff;color:#2d2d2d;font:11px/normal sans-serif;cursor:pointer;outline:0;background-color:#f1f1f1;border-radius:2px;zoom:1;line-height:1.3}div#driver-popover-item .driver-popover-footer button.driver-disabled{color:grey;cursor:default;pointer-events:none}div#driver-popover-item .driver-popover-footer .driver-close-btn{float:left}div#driver-popover-item .driver-popover-footer .driver-btn-group,div#driver-popover-item .driver-popover-footer .driver-close-only-btn{float:right}div#driver-popover-item .driver-popover-title{font:19px/normal sans-serif;margin:0 0 5px;font-weight:700;display:block;position:relative;line-height:1.5;zoom:1}div#driver-popover-item .driver-popover-description{margin-bottom:0;font:14px/normal sans-serif;line-height:1.5;color:#2d2d2d;font-weight:400;zoom:1}.driver-clearfix:after,.driver-clearfix:before{content:"";display:table}.driver-clearfix:after{clear:both}.driver-stage-no-animation{transition:none!important;background:transparent!important;outline:5000px solid rgba(0,0,0,.75)}div#driver-page-overlay{background:#000;position:fixed;top:0;left:0;bottom:0;right:0;display:block;width:100%;height:100%;zoom:1;filter:alpha(opacity=75);opacity:.75;z-index:100002!important;transition:all .3s}div#driver-highlighted-element-stage{position:absolute;top:0;left:0;height:50px;width:300px;background:#fff;z-index:100003!important;display:none;border-radius:2px;transition:all .3s}.driver-highlighted-element{z-index:100004!important}.driver-position-relative{position:relative!important}.driver-fix-stacking{z-index:auto!important;opacity:1!important;transform:none!important;-webkit-filter:none!important;filter:none!important;perspective:none!important;transform-style:flat!important;transform-box:border-box!important;will-change:unset!important}
 
 
dist/driver.min.js DELETED
@@ -1,2 +0,0 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Driver=e():t.Driver=e()}(window,function(){return function(t){var e={};function n(o){if(e[o])return e[o].exports;var i=e[o]={i:o,l:!1,exports:{}};return t[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(o,i,function(e){return t[e]}.bind(null,i));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/dist/",n(n.s=57)}([function(t,e,n){var o=n(2),i=n(11),r=n(4),s=n(13),a=n(22),c=function(t,e,n){var u,l,h,f,p=t&c.F,d=t&c.G,v=t&c.S,y=t&c.P,g=t&c.B,m=d?o:v?o[e]||(o[e]={}):(o[e]||{}).prototype,b=d?i:i[e]||(i[e]={}),w=b.prototype||(b.prototype={});for(u in d&&(n=e),n)h=((l=!p&&m&&void 0!==m[u])?m:n)[u],f=g&&l?a(h,o):y&&"function"==typeof h?a(Function.call,h):h,m&&s(m,u,h,t&c.U),b[u]!=h&&r(b,u,f),y&&w[u]!=h&&(w[u]=h)};o.core=i,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,t.exports=c},function(t,e,n){var o=n(17)("wks"),i=n(14),r=n(2).Symbol,s="function"==typeof r;(t.exports=function(t){return o[t]||(o[t]=s&&r[t]||(s?r:i)("Symbol."+t))}).store=o},function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var o=n(5),i=n(16);t.exports=n(6)?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var o=n(12),i=n(35),r=n(21),s=Object.defineProperty;e.f=n(6)?Object.defineProperty:function(t,e,n){if(o(t),e=r(e,!0),o(n),i)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){t.exports=!n(7)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var o=n(39),i=n(24);t.exports=function(t){return o(i(t))}},function(t,e,n){var o=n(0);o(o.S+o.F*!n(6),"Object",{defineProperty:n(5).f})},function(t,e){var n=t.exports={version:"2.6.9"};"number"==typeof __e&&(__e=n)},function(t,e,n){var o=n(3);t.exports=function(t){if(!o(t))throw TypeError(t+" is not an object!");return t}},function(t,e,n){var o=n(2),i=n(4),r=n(8),s=n(14)("src"),a=n(59),c=(""+a).split("toString");n(11).inspectSource=function(t){return a.call(t)},(t.exports=function(t,e,n,a){var u="function"==typeof n;u&&(r(n,"name")||i(n,"name",e)),t[e]!==n&&(u&&(r(n,s)||i(n,s,t[e]?""+t[e]:c.join(String(e)))),t===o?t[e]=n:a?t[e]?t[e]=n:i(t,e,n):(delete t[e],i(t,e,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[s]||a.call(this)})},function(t,e){var n=0,o=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+o).toString(36))}},function(t,e,n){var o=n(45),i=n(28);t.exports=Object.keys||function(t){return o(t,i)}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var o=n(11),i=n(2),r=i["__core-js_shared__"]||(i["__core-js_shared__"]={});(t.exports=function(t,e){return r[t]||(r[t]=void 0!==e?e:{})})("versions",[]).push({version:o.version,mode:n(18)?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e){t.exports=!1},function(t,e,n){var o=n(24);t.exports=function(t){return Object(o(t))}},function(t,e,n){"use strict";var o=n(2),i=n(8),r=n(6),s=n(0),a=n(13),c=n(62).KEY,u=n(7),l=n(17),h=n(26),f=n(14),p=n(1),d=n(43),v=n(44),y=n(63),g=n(42),m=n(12),b=n(3),w=n(19),x=n(9),S=n(21),O=n(16),k=n(30),P=n(67),E=n(49),N=n(47),j=n(5),L=n(15),T=E.f,C=j.f,_=P.f,M=o.Symbol,H=o.JSON,B=H&&H.stringify,F=p("_hidden"),I=p("toPrimitive"),R={}.propertyIsEnumerable,A=l("symbol-registry"),z=l("symbols"),D=l("op-symbols"),V=Object.prototype,W="function"==typeof M&&!!N.f,q=o.QObject,G=!q||!q.prototype||!q.prototype.findChild,K=r&&u(function(){return 7!=k(C({},"a",{get:function(){return C(this,"a",{value:7}).a}})).a})?function(t,e,n){var o=T(V,e);o&&delete V[e],C(t,e,n),o&&t!==V&&C(V,e,o)}:C,U=function(t){var e=z[t]=k(M.prototype);return e._k=t,e},Y=W&&"symbol"==typeof M.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof M},J=function(t,e,n){return t===V&&J(D,e,n),m(t),e=S(e,!0),m(n),i(z,e)?(n.enumerable?(i(t,F)&&t[F][e]&&(t[F][e]=!1),n=k(n,{enumerable:O(0,!1)})):(i(t,F)||C(t,F,O(1,{})),t[F][e]=!0),K(t,e,n)):C(t,e,n)},X=function(t,e){m(t);for(var n,o=y(e=x(e)),i=0,r=o.length;r>i;)J(t,n=o[i++],e[n]);return t},Q=function(t){var e=R.call(this,t=S(t,!0));return!(this===V&&i(z,t)&&!i(D,t))&&(!(e||!i(this,t)||!i(z,t)||i(this,F)&&this[F][t])||e)},$=function(t,e){if(t=x(t),e=S(e,!0),t!==V||!i(z,e)||i(D,e)){var n=T(t,e);return!n||!i(z,e)||i(t,F)&&t[F][e]||(n.enumerable=!0),n}},Z=function(t){for(var e,n=_(x(t)),o=[],r=0;n.length>r;)i(z,e=n[r++])||e==F||e==c||o.push(e);return o},tt=function(t){for(var e,n=t===V,o=_(n?D:x(t)),r=[],s=0;o.length>s;)!i(z,e=o[s++])||n&&!i(V,e)||r.push(z[e]);return r};W||(a((M=function(){if(this instanceof M)throw TypeError("Symbol is not a constructor!");var t=f(arguments.length>0?arguments[0]:void 0),e=function(n){this===V&&e.call(D,n),i(this,F)&&i(this[F],t)&&(this[F][t]=!1),K(this,t,O(1,n))};return r&&G&&K(V,t,{configurable:!0,set:e}),U(t)}).prototype,"toString",function(){return this._k}),E.f=$,j.f=J,n(48).f=P.f=Z,n(29).f=Q,N.f=tt,r&&!n(18)&&a(V,"propertyIsEnumerable",Q,!0),d.f=function(t){return U(p(t))}),s(s.G+s.W+s.F*!W,{Symbol:M});for(var et="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),nt=0;et.length>nt;)p(et[nt++]);for(var ot=L(p.store),it=0;ot.length>it;)v(ot[it++]);s(s.S+s.F*!W,"Symbol",{for:function(t){return i(A,t+="")?A[t]:A[t]=M(t)},keyFor:function(t){if(!Y(t))throw TypeError(t+" is not a symbol!");for(var e in A)if(A[e]===t)return e},useSetter:function(){G=!0},useSimple:function(){G=!1}}),s(s.S+s.F*!W,"Object",{create:function(t,e){return void 0===e?k(t):X(k(t),e)},defineProperty:J,defineProperties:X,getOwnPropertyDescriptor:$,getOwnPropertyNames:Z,getOwnPropertySymbols:tt});var rt=u(function(){N.f(1)});s(s.S+s.F*rt,"Object",{getOwnPropertySymbols:function(t){return N.f(w(t))}}),H&&s(s.S+s.F*(!W||u(function(){var t=M();return"[null]"!=B([t])||"{}"!=B({a:t})||"{}"!=B(Object(t))})),"JSON",{stringify:function(t){for(var e,n,o=[t],i=1;arguments.length>i;)o.push(arguments[i++]);if(n=e=o[1],(b(e)||void 0!==t)&&!Y(t))return g(e)||(e=function(t,e){if("function"==typeof n&&(e=n.call(this,t,e)),!Y(e))return e}),o[1]=e,B.apply(H,o)}}),M.prototype[I]||n(4)(M.prototype,I,M.prototype.valueOf),h(M,"Symbol"),h(Math,"Math",!0),h(o.JSON,"JSON",!0)},function(t,e,n){var o=n(3);t.exports=function(t,e){if(!o(t))return t;var n,i;if(e&&"function"==typeof(n=t.toString)&&!o(i=n.call(t)))return i;if("function"==typeof(n=t.valueOf)&&!o(i=n.call(t)))return i;if(!e&&"function"==typeof(n=t.toString)&&!o(i=n.call(t)))return i;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var o=n(37);t.exports=function(t,e,n){if(o(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,o){return t.call(e,n,o)};case 3:return function(n,o,i){return t.call(e,n,o,i)}}return function(){return t.apply(e,arguments)}}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var o=n(7);t.exports=function(t,e){return!!t&&o(function(){e?t.call(null,function(){},1):t.call(null)})}},function(t,e,n){var o=n(5).f,i=n(8),r=n(1)("toStringTag");t.exports=function(t,e,n){t&&!i(t=n?t:t.prototype,r)&&o(t,r,{configurable:!0,value:e})}},function(t,e,n){var o=n(17)("keys"),i=n(14);t.exports=function(t){return o[t]||(o[t]=i(t))}},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,e){e.f={}.propertyIsEnumerable},function(t,e,n){var o=n(12),i=n(65),r=n(28),s=n(27)("IE_PROTO"),a=function(){},c=function(){var t,e=n(36)("iframe"),o=r.length;for(e.style.display="none",n(66).appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write("<script>document.F=Object<\/script>"),t.close(),c=t.F;o--;)delete c.prototype[r[o]];return c()};t.exports=Object.create||function(t,e){var n;return null!==t?(a.prototype=o(t),n=new a,a.prototype=null,n[s]=t):n=c(),void 0===e?n:i(n,e)}},function(t,e,n){"use strict";var o=n(68),i=n(69),r=n(32),s=n(9);t.exports=n(70)(Array,"Array",function(t,e){this._t=s(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,i(1)):i(0,"keys"==e?n:"values"==e?t[n]:[n,t[n]])},"values"),r.Arguments=r.Array,o("keys"),o("values"),o("entries")},function(t,e){t.exports={}},function(t,e,n){n(44)("asyncIterator")},function(t,e,n){"use strict";var o=n(0),i=n(38)(0),r=n(25)([].forEach,!0);o(o.P+o.F*!r,"Array",{forEach:function(t){return i(this,t,arguments[1])}})},function(t,e,n){t.exports=!n(6)&&!n(7)(function(){return 7!=Object.defineProperty(n(36)("div"),"a",{get:function(){return 7}}).a})},function(t,e,n){var o=n(3),i=n(2).document,r=o(i)&&o(i.createElement);t.exports=function(t){return r?i.createElement(t):{}}},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e,n){var o=n(22),i=n(39),r=n(19),s=n(40),a=n(60);t.exports=function(t,e){var n=1==t,c=2==t,u=3==t,l=4==t,h=6==t,f=5==t||h,p=e||a;return function(e,a,d){for(var v,y,g=r(e),m=i(g),b=o(a,d,3),w=s(m.length),x=0,S=n?p(e,w):c?p(e,0):void 0;w>x;x++)if((f||x in m)&&(y=b(v=m[x],x,g),t))if(n)S[x]=y;else if(y)switch(t){case 3:return!0;case 5:return v;case 6:return x;case 2:S.push(v)}else if(l)return!1;return h?-1:u||l?l:S}}},function(t,e,n){var o=n(23);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==o(t)?t.split(""):Object(t)}},function(t,e,n){var o=n(41),i=Math.min;t.exports=function(t){return t>0?i(o(t),9007199254740991):0}},function(t,e){var n=Math.ceil,o=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?o:n)(t)}},function(t,e,n){var o=n(23);t.exports=Array.isArray||function(t){return"Array"==o(t)}},function(t,e,n){e.f=n(1)},function(t,e,n){var o=n(2),i=n(11),r=n(18),s=n(43),a=n(5).f;t.exports=function(t){var e=i.Symbol||(i.Symbol=r?{}:o.Symbol||{});"_"==t.charAt(0)||t in e||a(e,t,{value:s.f(t)})}},function(t,e,n){var o=n(8),i=n(9),r=n(46)(!1),s=n(27)("IE_PROTO");t.exports=function(t,e){var n,a=i(t),c=0,u=[];for(n in a)n!=s&&o(a,n)&&u.push(n);for(;e.length>c;)o(a,n=e[c++])&&(~r(u,n)||u.push(n));return u}},function(t,e,n){var o=n(9),i=n(40),r=n(64);t.exports=function(t){return function(e,n,s){var a,c=o(e),u=i(c.length),l=r(s,u);if(t&&n!=n){for(;u>l;)if((a=c[l++])!=a)return!0}else for(;u>l;l++)if((t||l in c)&&c[l]===n)return t||l||0;return!t&&-1}}},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){var o=n(45),i=n(28).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return o(t,i)}},function(t,e,n){var o=n(29),i=n(16),r=n(9),s=n(21),a=n(8),c=n(35),u=Object.getOwnPropertyDescriptor;e.f=n(6)?u:function(t,e){if(t=r(t),e=s(e,!0),c)try{return u(t,e)}catch(t){}if(a(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e,n){for(var o=n(31),i=n(15),r=n(13),s=n(2),a=n(4),c=n(32),u=n(1),l=u("iterator"),h=u("toStringTag"),f=c.Array,p={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},d=i(p),v=0;v<d.length;v++){var y,g=d[v],m=p[g],b=s[g],w=b&&b.prototype;if(w&&(w[l]||a(w,l,f),w[h]||a(w,h,g),c[g]=f,m))for(y in o)w[y]||r(w,y,o[y],!0)}},function(t,e,n){"use strict";var o=n(73),i={};i[n(1)("toStringTag")]="z",i+""!="[object z]"&&n(13)(Object.prototype,"toString",function(){return"[object "+o(this)+"]"},!0)},function(t,e,n){var o=n(19),i=n(15);n(74)("keys",function(){return function(t){return i(o(t))}})},function(t,e,n){"use strict";var o=n(0),i=n(38)(2);o(o.P+o.F*!n(25)([].filter,!0),"Array",{filter:function(t){return i(this,t,arguments[1])}})},function(t,e,n){var o=n(0);o(o.P,"Function",{bind:n(75)})},function(t,e,n){var o=n(0);o(o.S,"Object",{create:n(30)})},function(t,e,n){var o=n(0);o(o.S,"Object",{setPrototypeOf:n(81).set})},function(t,e,n){n(58),t.exports=n(82)},function(t,e){},function(t,e,n){t.exports=n(17)("native-function-to-string",Function.toString)},function(t,e,n){var o=n(61);t.exports=function(t,e){return new(o(t))(e)}},function(t,e,n){var o=n(3),i=n(42),r=n(1)("species");t.exports=function(t){var e;return i(t)&&("function"!=typeof(e=t.constructor)||e!==Array&&!i(e.prototype)||(e=void 0),o(e)&&null===(e=e[r])&&(e=void 0)),void 0===e?Array:e}},function(t,e,n){var o=n(14)("meta"),i=n(3),r=n(8),s=n(5).f,a=0,c=Object.isExtensible||function(){return!0},u=!n(7)(function(){return c(Object.preventExtensions({}))}),l=function(t){s(t,o,{value:{i:"O"+ ++a,w:{}}})},h=t.exports={KEY:o,NEED:!1,fastKey:function(t,e){if(!i(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!r(t,o)){if(!c(t))return"F";if(!e)return"E";l(t)}return t[o].i},getWeak:function(t,e){if(!r(t,o)){if(!c(t))return!0;if(!e)return!1;l(t)}return t[o].w},onFreeze:function(t){return u&&h.NEED&&c(t)&&!r(t,o)&&l(t),t}}},function(t,e,n){var o=n(15),i=n(47),r=n(29);t.exports=function(t){var e=o(t),n=i.f;if(n)for(var s,a=n(t),c=r.f,u=0;a.length>u;)c.call(t,s=a[u++])&&e.push(s);return e}},function(t,e,n){var o=n(41),i=Math.max,r=Math.min;t.exports=function(t,e){return(t=o(t))<0?i(t+e,0):r(t,e)}},function(t,e,n){var o=n(5),i=n(12),r=n(15);t.exports=n(6)?Object.defineProperties:function(t,e){i(t);for(var n,s=r(e),a=s.length,c=0;a>c;)o.f(t,n=s[c++],e[n]);return t}},function(t,e,n){var o=n(2).document;t.exports=o&&o.documentElement},function(t,e,n){var o=n(9),i=n(48).f,r={}.toString,s="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[];t.exports.f=function(t){return s&&"[object Window]"==r.call(t)?function(t){try{return i(t)}catch(t){return s.slice()}}(t):i(o(t))}},function(t,e,n){var o=n(1)("unscopables"),i=Array.prototype;null==i[o]&&n(4)(i,o,{}),t.exports=function(t){i[o][t]=!0}},function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},function(t,e,n){"use strict";var o=n(18),i=n(0),r=n(13),s=n(4),a=n(32),c=n(71),u=n(26),l=n(72),h=n(1)("iterator"),f=!([].keys&&"next"in[].keys()),p=function(){return this};t.exports=function(t,e,n,d,v,y,g){c(n,e,d);var m,b,w,x=function(t){if(!f&&t in P)return P[t];switch(t){case"keys":case"values":return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+" Iterator",O="values"==v,k=!1,P=t.prototype,E=P[h]||P["@@iterator"]||v&&P[v],N=E||x(v),j=v?O?x("entries"):N:void 0,L="Array"==e&&P.entries||E;if(L&&(w=l(L.call(new t)))!==Object.prototype&&w.next&&(u(w,S,!0),o||"function"==typeof w[h]||s(w,h,p)),O&&E&&"values"!==E.name&&(k=!0,N=function(){return E.call(this)}),o&&!g||!f&&!k&&P[h]||s(P,h,N),a[e]=N,a[S]=p,v)if(m={values:O?N:x("values"),keys:y?N:x("keys"),entries:j},g)for(b in m)b in P||r(P,b,m[b]);else i(i.P+i.F*(f||k),e,m);return m}},function(t,e,n){"use strict";var o=n(30),i=n(16),r=n(26),s={};n(4)(s,n(1)("iterator"),function(){return this}),t.exports=function(t,e,n){t.prototype=o(s,{next:i(1,n)}),r(t,e+" Iterator")}},function(t,e,n){var o=n(8),i=n(19),r=n(27)("IE_PROTO"),s=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=i(t),o(t,r)?t[r]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?s:null}},function(t,e,n){var o=n(23),i=n(1)("toStringTag"),r="Arguments"==o(function(){return arguments}());t.exports=function(t){var e,n,s;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),i))?n:r?o(e):"Object"==(s=o(e))&&"function"==typeof e.callee?"Arguments":s}},function(t,e,n){var o=n(0),i=n(11),r=n(7);t.exports=function(t,e){var n=(i.Object||{})[t]||Object[t],s={};s[t]=e(n),o(o.S+o.F*r(function(){n(1)}),"Object",s)}},function(t,e,n){"use strict";var o=n(37),i=n(3),r=n(76),s=[].slice,a={};t.exports=Function.bind||function(t){var e=o(this),n=s.call(arguments,1),c=function(){var o=n.concat(s.call(arguments));return this instanceof c?function(t,e,n){if(!(e in a)){for(var o=[],i=0;i<e;i++)o[i]="a["+i+"]";a[e]=Function("F,a","return new F("+o.join(",")+")")}return a[e](t,n)}(e,o.length,o):r(e,o,t)};return i(e.prototype)&&(c.prototype=e.prototype),c}},function(t,e){t.exports=function(t,e,n){var o=void 0===n;switch(e.length){case 0:return o?t():t.call(n);case 1:return o?t(e[0]):t.call(n,e[0]);case 2:return o?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return o?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return o?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},function(t,e,n){"use strict";n(78)("trim",function(t){return function(){return t(this,3)}})},function(t,e,n){var o=n(0),i=n(24),r=n(7),s=n(79),a="["+s+"]",c=RegExp("^"+a+a+"*"),u=RegExp(a+a+"*$"),l=function(t,e,n){var i={},a=r(function(){return!!s[t]()||"​…"!="​…"[t]()}),c=i[t]=a?e(h):s[t];n&&(i[n]=c),o(o.P+o.F*a,"String",i)},h=l.trim=function(t,e){return t=String(i(t)),1&e&&(t=t.replace(c,"")),2&e&&(t=t.replace(u,"")),t};t.exports=l},function(t,e){t.exports="\t\n\v\f\r   ᠎              \u2028\u2029\ufeff"},function(t,e,n){"use strict";var o=n(0),i=n(46)(!1),r=[].indexOf,s=!!r&&1/[1].indexOf(1,-0)<0;o(o.P+o.F*(s||!n(25)(r)),"Array",{indexOf:function(t){return s?r.apply(this,arguments)||0:i(this,t,arguments[1])}})},function(t,e,n){var o=n(3),i=n(12),r=function(t,e){if(i(t),!o(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,e,o){try{(o=n(22)(Function.call,n(49).f(Object.prototype,"__proto__").set,2))(t,[]),e=!(t instanceof Array)}catch(t){e=!0}return function(t,n){return r(t,n),e?t.__proto__=n:o(t,n),t}}({},!1):void 0),check:r}},function(t,e,n){"use strict";n.r(e);n(34),n(20),n(50),n(31),n(51),n(52),n(10),n(53),n(54);var o=.75,i=10,r=!0,s=!0,a=!0,c=!1,u="driver-highlighted-element-stage",l='<div id="'.concat("driver-page-overlay",'"></div>'),h='<div id="'.concat(u,'"></div>');n(33),n(77);function f(t){return(f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var p=function(t){var e=document.createElement("div");return e.innerHTML=t.trim(),e.firstChild},d=function t(e,n){if(arguments.length>2&&void 0!==arguments[2]&&arguments[2]){for(var o=["","-webkit-","-ms-","moz-","-o-"],i=0;i<o.length;i++){var r=t(e,o[i]+n);if(r)return r}return""}var s="";return e.currentStyle?s=e.currentStyle[n]:document.defaultView&&document.defaultView.getComputedStyle&&(s=document.defaultView.getComputedStyle(e,null).getPropertyValue(n)),s&&s.toLowerCase?s.toLowerCase():s},v=function(t){return t&&"object"===f(t)&&"nodeType"in t};function y(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var g=function(){function t(e,n,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.options=e,this.highlightedElement=null,this.lastHighlightedElement=null,this.hideTimer=null,this.window=n,this.document=o,this.removeNode=this.removeNode.bind(this)}var e,n,o;return e=t,(n=[{key:"attachNode",value:function(){var t=this.document.getElementById("driver-page-overlay");t||(t=p(l),document.body.appendChild(t)),this.node=t,this.node.style.opacity="0",this.options.animate||this.node.parentElement&&this.node.parentElement.removeChild(this.node)}},{key:"highlight",value:function(t){t&&t.node?t.isSame(this.highlightedElement)||(this.window.clearTimeout(this.hideTimer),t.onHighlightStarted(),this.highlightedElement&&!this.highlightedElement.isSame(this.lastHighlightedElement)&&this.highlightedElement.onDeselected(),t.getCalculatedPosition().canHighlight()&&(this.lastHighlightedElement=this.highlightedElement,this.highlightedElement=t,this.show(),this.highlightedElement.onHighlighted())):console.warn("Invalid element to highlight. Must be an instance of `Element`")}},{key:"show",value:function(){var t=this;this.node&&this.node.parentElement||(this.attachNode(),window.setTimeout(function(){t.node.style.opacity="".concat(t.options.opacity),t.node.style.position="fixed",t.node.style.left="0",t.node.style.top="0",t.node.style.bottom="0",t.node.style.right="0"}))}},{key:"getHighlightedElement",value:function(){return this.highlightedElement}},{key:"getLastHighlightedElement",value:function(){return this.lastHighlightedElement}},{key:"clear",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(this.options.onReset&&this.options.onReset(this.highlightedElement),this.highlightedElement){this.highlightedElement.onDeselected(!0)}this.highlightedElement=null,this.lastHighlightedElement=null,this.node&&(this.window.clearTimeout(this.hideTimer),this.options.animate&&!t?(this.node.style.opacity="0",this.hideTimer=this.window.setTimeout(this.removeNode,300)):this.removeNode())}},{key:"removeNode",value:function(){this.node&&this.node.parentElement&&this.node.parentElement.removeChild(this.node)}},{key:"refresh",value:function(){this.highlightedElement&&(this.highlightedElement.showPopover(),this.highlightedElement.showStage())}}])&&y(e.prototype,n),o&&y(e,o),t}();n(80);function m(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var b=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.left,o=void 0===n?0:n,i=e.top,r=void 0===i?0:i,s=e.right,a=void 0===s?0:s,c=e.bottom,u=void 0===c?0:c;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.left=o,this.right=a,this.top=r,this.bottom=u}var e,n,o;return e=t,(n=[{key:"canHighlight",value:function(){return this.left<this.right&&this.top<this.bottom}}])&&m(e.prototype,n),o&&m(e,o),t}();function w(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var x=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.node,o=e.options,i=e.popover,r=e.stage,s=e.overlay,a=e.window,c=e.document;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.node=n,this.document=c,this.window=a,this.options=o,this.overlay=s,this.popover=i,this.stage=r,this.animationTimeout=null}var e,n,o;return e=t,(n=[{key:"isInView",value:function(){for(var t=this.node.offsetTop,e=this.node.offsetLeft,n=this.node.offsetWidth,o=this.node.offsetHeight,i=this.node;i.offsetParent;)t+=(i=i.offsetParent).offsetTop,e+=i.offsetLeft;return t>=this.window.pageYOffset&&e>=this.window.pageXOffset&&t+o<=this.window.pageYOffset+this.window.innerHeight&&e+n<=this.window.pageXOffset+this.window.innerWidth}},{key:"scrollManually",value:function(){var t=this.node.getBoundingClientRect().top+this.window.pageYOffset-this.window.innerHeight/2;this.window.scrollTo(0,t)}},{key:"bringInView",value:function(){if(this.node&&!this.isInView())if(this.node.scrollIntoView)try{this.node.scrollIntoView(this.options.scrollIntoViewOptions||{behavior:"instant",block:"center"})}catch(t){this.scrollManually()}else this.scrollManually()}},{key:"getCalculatedPosition",value:function(){var t=this.document.body,e=this.document.documentElement,n=this.window,o=this.window.pageYOffset||e.scrollTop||t.scrollTop,i=n.pageXOffset||e.scrollLeft||t.scrollLeft,r=this.node.getBoundingClientRect();return new b({top:r.top+o,left:r.left+i,right:r.left+i+r.width,bottom:r.top+o+r.height})}},{key:"getPopover",value:function(){return this.popover}},{key:"onDeselected",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.hidePopover(),t&&this.hideStage(),this.removeHighlightClasses(),this.window.clearTimeout(this.animationTimeout),this.options.onDeselected&&this.options.onDeselected(this)}},{key:"isSame",value:function(t){return!(!t||!t.node)&&t.node===this.node}},{key:"onHighlightStarted",value:function(){this.options.onHighlightStarted&&this.options.onHighlightStarted(this)}},{key:"onHighlighted",value:function(){this.isInView()||this.bringInView(),this.showPopover(),this.showStage(),this.addHighlightClasses(),this.options.onHighlighted&&this.options.onHighlighted(this)}},{key:"removeHighlightClasses",value:function(){this.node.classList.remove("driver-highlighted-element"),this.node.classList.remove("driver-position-relative");for(var t=this.document.querySelectorAll(".".concat("driver-fix-stacking")),e=0;e<t.length;e++)t[e].classList.remove("driver-fix-stacking")}},{key:"addHighlightClasses",value:function(){this.node.classList.add("driver-highlighted-element"),this.canMakeRelative()&&this.node.classList.add("driver-position-relative"),this.fixStackingContext()}},{key:"fixStackingContext",value:function(){for(var t=this.node.parentNode;t&&t.tagName&&"body"!==t.tagName.toLowerCase();){var e=d(t,"z-index"),n=parseFloat(d(t,"opacity")),o=d(t,"transform",!0),i=d(t,"transform-style",!0),r=d(t,"transform-box",!0),s=d(t,"filter",!0),a=d(t,"perspective",!0);(/[0-9]+/.test(e)||n<1||o&&"none"!==o||i&&"flat"!==i||r&&"border-box"!==r||s&&"none"!==s||a&&"none"!==a)&&t.classList.add("driver-fix-stacking"),t=t.parentNode}}},{key:"canMakeRelative",value:function(){var t=this.getStyleProperty("position");return-1===["absolute","fixed","relative"].indexOf(t)}},{key:"getStyleProperty",value:function(t){return d(this.node,t)}},{key:"showStage",value:function(){this.stage.show(this.getCalculatedPosition())}},{key:"getNode",value:function(){return this.node}},{key:"hideStage",value:function(){this.stage.hide()}},{key:"hidePopover",value:function(){this.popover&&this.popover.hide()}},{key:"showPopover",value:function(){var t=this;if(this.popover){var e=this.getCalculatedPosition(),n=300;this.options.animate&&this.overlay.lastHighlightedElement||(n=0),this.animationTimeout=this.window.setTimeout(function(){t.popover.show(e)},n)}}},{key:"getFullPageSize",value:function(){var t=this.document.body,e=this.document.documentElement;return{height:Math.max(t.scrollHeight,t.offsetHeight,e.scrollHeight,e.offsetHeight),width:Math.max(t.scrollWidth,t.offsetWidth,e.scrollWidth,e.offsetWidth)}}},{key:"getSize",value:function(){return{height:Math.max(this.node.scrollHeight,this.node.offsetHeight),width:Math.max(this.node.scrollWidth,this.node.offsetWidth)}}}])&&w(e.prototype,n),o&&w(e,o),t}();n(55),n(56);function S(t){return(S="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function O(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function k(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function P(t,e){return!e||"object"!==S(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function E(t){return(E=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function N(t,e){return(N=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}var j=function(t){function e(t,n,o){var i;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),(i=P(this,E(e).call(this))).options=function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),o.forEach(function(e){O(t,e,n[e])})}return t}({isFirst:!0,isLast:!0,totalCount:1,currentIndex:0,offset:0,showButtons:!0,closeBtnText:"Close",doneBtnText:"Done",startBtnText:"Next &rarr;",nextBtnText:"Next &rarr;",prevBtnText:"&larr; Previous"},t),i.window=n,i.document=o,i}var n,o,i;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&N(t,e)}(e,x),n=e,(o=[{key:"attachNode",value:function(){var t=this.document.getElementById("driver-popover-item");t&&t.parentElement.removeChild(t),t=p(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return'\n <div id="'.concat("driver-popover-item",'" class="').concat(t,'">\n <div class="').concat("driver-popover-tip",'"></div>\n <div class="').concat("driver-popover-title",'">Popover Title</div>\n <div class="').concat("driver-popover-description",'">Popover Description</div>\n <div class="driver-clearfix ').concat("driver-popover-footer",'">\n <button class="').concat("driver-close-btn",'">Close</button>\n <span class="driver-btn-group ').concat("driver-navigation-btns",'">\n <button class="').concat("driver-prev-btn",'">&larr; Previous</button>\n <button class="').concat("driver-next-btn",'">Next &rarr;</button>\n </span>\n </div>\n </div>')}(this.options.className)),document.body.appendChild(t),this.node=t,this.tipNode=t.querySelector(".".concat("driver-popover-tip")),this.titleNode=t.querySelector(".".concat("driver-popover-title")),this.descriptionNode=t.querySelector(".".concat("driver-popover-description")),this.footerNode=t.querySelector(".".concat("driver-popover-footer")),this.nextBtnNode=t.querySelector(".".concat("driver-next-btn")),this.prevBtnNode=t.querySelector(".".concat("driver-prev-btn")),this.closeBtnNode=t.querySelector(".".concat("driver-close-btn"))}},{key:"getTitleNode",value:function(){return this.titleNode}},{key:"getDescriptionNode",value:function(){return this.descriptionNode}},{key:"hide",value:function(){this.node&&(this.node.style.display="none")}},{key:"setInitialState",value:function(){this.node.style.display="block",this.node.style.left="0",this.node.style.top="0",this.node.style.bottom="",this.node.style.right="",this.node.querySelector(".".concat("driver-popover-tip")).className="driver-popover-tip"}},{key:"show",value:function(t){switch(this.attachNode(),this.setInitialState(),this.titleNode.innerHTML=this.options.title,this.descriptionNode.innerHTML=this.options.description||"",this.renderFooter(),this.options.position){case"left":case"left-top":this.positionOnLeft(t);break;case"left-center":this.positionOnLeftCenter(t);break;case"left-bottom":this.positionOnLeftBottom(t);break;case"right":case"right-top":this.positionOnRight(t);break;case"right-center":this.positionOnRightCenter(t);break;case"right-bottom":this.positionOnRightBottom(t);break;case"top":case"top-left":this.positionOnTop(t);break;case"top-center":this.positionOnTopCenter(t);break;case"top-right":this.positionOnTopRight(t);break;case"bottom":case"bottom-left":this.positionOnBottom(t);break;case"bottom-center":this.positionOnBottomCenter(t);break;case"bottom-right":this.positionOnBottomRight(t);break;case"mid-center":this.positionOnMidCenter(t);break;case"auto":default:this.autoPosition(t)}this.bringInView()}},{key:"renderFooter",value:function(){this.nextBtnNode.innerHTML=this.options.nextBtnText,this.prevBtnNode.innerHTML=this.options.prevBtnText,this.closeBtnNode.innerHTML=this.options.closeBtnText;var t=this.options.totalCount&&1!==this.options.totalCount;this.options.showButtons?(t?(this.nextBtnNode.style.display="inline-block",this.prevBtnNode.style.display="inline-block",this.closeBtnNode.classList.remove("driver-close-only-btn")):(this.nextBtnNode.style.display="none",this.prevBtnNode.style.display="none",this.closeBtnNode.classList.add("driver-close-only-btn")),this.footerNode.style.display="block",this.options.isFirst?(this.prevBtnNode.classList.add("driver-disabled"),this.nextBtnNode.innerHTML=this.options.startBtnText):this.prevBtnNode.classList.remove("driver-disabled"),this.options.isLast?this.nextBtnNode.innerHTML=this.options.doneBtnText:this.nextBtnNode.innerHTML=this.options.nextBtnText):this.footerNode.style.display="none"}},{key:"positionOnLeft",value:function(t){var e=this.getSize().width,n=this.options.padding+10;this.node.style.left="".concat(t.left-e-n,"px"),this.node.style.top="".concat(t.top+this.options.offset-this.options.padding,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("right")}},{key:"positionOnLeftBottom",value:function(t){var e=this.getSize(),n=e.width,o=this.options.padding+10;this.node.style.left="".concat(t.left-n-o,"px"),this.node.style.top="".concat(t.bottom+this.options.padding+this.options.offset-e.height,"px"),this.node.style.bottom="",this.node.style.right="",this.tipNode.classList.add("right","position-bottom")}},{key:"positionOnLeftCenter",value:function(t){var e=this.getSize(),n=e.width,o=e.height/2,i=this.options.padding+10,r=(t.bottom-t.top)/2,s=t.top-o+r+this.options.offset;this.node.style.left="".concat(t.left-n-i,"px"),this.node.style.top="".concat(s,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("right","position-center")}},{key:"positionOnRight",value:function(t){var e=this.options.padding+10;this.node.style.left="".concat(t.right+e,"px"),this.node.style.top="".concat(t.top+this.options.offset-this.options.padding,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("left")}},{key:"positionOnRightCenter",value:function(t){var e=this.getSize(),n=this.options.padding+10,o=e.height/2,i=(t.bottom-t.top)/2,r=t.top-o+i+this.options.offset;this.node.style.left="".concat(t.right+n,"px"),this.node.style.top="".concat(r,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("left","position-center")}},{key:"positionOnRightBottom",value:function(t){var e=this.options.padding+10,n=this.getSize();this.node.style.left="".concat(t.right+e,"px"),this.node.style.top="".concat(t.bottom+this.options.padding+this.options.offset-n.height,"px"),this.node.style.bottom="",this.node.style.right="",this.tipNode.classList.add("left","position-bottom")}},{key:"positionOnTop",value:function(t){var e=this.getSize().height,n=this.options.padding+10;this.node.style.top="".concat(t.top-e-n,"px"),this.node.style.left="".concat(t.left-this.options.padding+this.options.offset,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("bottom")}},{key:"positionOnTopCenter",value:function(t){var e=this.getSize(),n=e.height,o=e.width/2,i=this.options.padding+10,r=this.options.offset+t.left+(t.right-t.left)/2;this.node.style.top="".concat(t.top-n-i,"px"),this.node.style.left="".concat(r-o-this.options.padding,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("bottom","position-center")}},{key:"positionOnTopRight",value:function(t){var e=this.getSize(),n=e.height,o=this.options.padding+10;this.node.style.top="".concat(t.top-n-o,"px"),this.node.style.left="".concat(t.right+this.options.padding+this.options.offset-e.width,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("bottom","position-right")}},{key:"positionOnBottom",value:function(t){var e=this.options.padding+10;this.node.style.top="".concat(t.bottom+e,"px"),this.node.style.left="".concat(t.left-this.options.padding+this.options.offset,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("top")}},{key:"positionOnBottomCenter",value:function(t){var e=this.getSize().width/2,n=this.options.padding+10,o=this.options.offset+t.left+(t.right-t.left)/2;this.node.style.top="".concat(t.bottom+n,"px"),this.node.style.left="".concat(o-e-this.options.padding,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("top","position-center")}},{key:"positionOnBottomRight",value:function(t){var e=this.getSize(),n=this.options.padding+10;this.node.style.top="".concat(t.bottom+n,"px"),this.node.style.left="".concat(t.right+this.options.padding+this.options.offset-e.width,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("top","position-right")}},{key:"positionOnMidCenter",value:function(t){var e=this.getSize(),n=e.height,o=e.width/2,i=n/2,r=(t.bottom-t.top)/2,s=t.top-i+r+this.options.offset,a=this.options.offset+t.left+(t.right-t.left)/2;this.node.style.top="".concat(s,"px"),this.node.style.left="".concat(a-o-this.options.padding,"px"),this.node.style.right="",this.node.style.bottom="",this.tipNode.classList.add("mid-center")}},{key:"autoPosition",value:function(t){var e=this.getFullPageSize(),n=this.getSize(),o=e.height,i=n.height,r=this.options.padding+10;t.bottom+i+r>=o?this.positionOnTop(t):this.positionOnBottom(t)}}])&&k(n.prototype,o),i&&k(n,i),e}();function L(t){return(L="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function T(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function C(t,e){return!e||"object"!==L(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function _(t){return(_=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function M(t,e){return(M=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}var H=function(t){function e(t,n,o){var i;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),(i=C(this,_(e).call(this))).options=t,i.window=n,i.document=o,i}var n,o,i;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&M(t,e)}(e,x),n=e,(o=[{key:"attachNode",value:function(){var t=this.document.getElementById(u);t||(t=p(h),document.body.appendChild(t)),this.node=t,this.options.animate?this.node.classList.remove("driver-stage-no-animation"):this.node.classList.add("driver-stage-no-animation")}},{key:"hide",value:function(){this.node&&this.node.parentElement&&this.node.parentElement.removeChild(this.node)}},{key:"setInitialStyle",value:function(){this.node.style.display="block",this.node.style.left="0",this.node.style.top="0",this.node.style.bottom="",this.node.style.right=""}},{key:"show",value:function(t){this.attachNode(),this.setInitialStyle();var e=2*this.options.padding,n=t.right-t.left+e,o=t.bottom-t.top+e;this.node.style.display="block",this.node.style.position="absolute",this.node.style.width="".concat(n,"px"),this.node.style.height="".concat(o,"px"),this.node.style.top="".concat(t.top-e/2,"px"),this.node.style.left="".concat(t.left-e/2,"px"),this.node.style.backgroundColor=this.options.stageBackground}}])&&T(n.prototype,o),i&&T(n,i),e}();function B(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),o.forEach(function(e){F(t,e,n[e])})}return t}function F(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function I(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}n.d(e,"default",function(){return R});var R=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.options=B({animate:r,opacity:o,padding:i,scrollIntoViewOptions:null,allowClose:s,keyboardControl:a,overlayClickNext:c,stageBackground:"#ffffff",onHighlightStarted:function(){return null},onHighlighted:function(){return null},onDeselected:function(){return null},onReset:function(){return null},onNext:function(){return null},onPrevious:function(){return null}},e),this.document=document,this.window=window,this.isActivated=!1,this.steps=[],this.currentStep=0,this.currentMovePrevented=!1,this.overlay=new g(this.options,window,document),this.onResize=this.onResize.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onClick=this.onClick.bind(this),this.moveNext=this.moveNext.bind(this),this.movePrevious=this.movePrevious.bind(this),this.preventMove=this.preventMove.bind(this),this.bind()}var e,n,u;return e=t,(n=[{key:"getSteps",value:function(){return this.steps}},{key:"setSteps",value:function(t){this.steps=t}},{key:"bind",value:function(){this.window.addEventListener("resize",this.onResize,!1),this.window.addEventListener("keyup",this.onKeyUp,!1),"ontouchstart"in document.documentElement?this.window.addEventListener("touchstart",this.onClick,!1):this.window.addEventListener("click",this.onClick,!1)}},{key:"onClick",value:function(t){if(this.isActivated&&this.hasHighlightedElement()){t.stopPropagation();var e=this.overlay.getHighlightedElement(),n=this.document.getElementById("driver-popover-item"),o=e.node.contains(t.target),i=n&&n.contains(t.target);if(o||i||!this.options.overlayClickNext)if(o||i||!this.options.allowClose){var r=t.target.classList.contains("driver-next-btn"),s=t.target.classList.contains("driver-prev-btn");t.target.classList.contains("driver-close-btn")?this.reset():r?this.handleNext():s&&this.handlePrevious()}else this.reset();else this.handleNext()}}},{key:"onResize",value:function(){this.isActivated&&this.refresh()}},{key:"refresh",value:function(){this.overlay.refresh()}},{key:"onKeyUp",value:function(t){if(this.isActivated&&this.options.keyboardControl)if(27!==t.keyCode){var e=this.getHighlightedElement();e&&e.popover&&(39===t.keyCode?this.handleNext():37===t.keyCode&&this.handlePrevious())}else this.reset()}},{key:"movePrevious",value:function(){var t=this.steps[this.currentStep-1];t?(this.overlay.highlight(t),this.currentStep-=1):this.reset()}},{key:"preventMove",value:function(){this.currentMovePrevented=!0}},{key:"handleNext",value:function(){this.currentMovePrevented=!1;var t=this.steps[this.currentStep];t&&t.options&&t.options.onNext&&t.options.onNext(this.overlay.highlightedElement),this.currentMovePrevented||this.moveNext()}},{key:"handlePrevious",value:function(){this.currentMovePrevented=!1;var t=this.steps[this.currentStep];t&&t.options&&t.options.onPrevious&&t.options.onPrevious(this.overlay.highlightedElement),this.currentMovePrevented||this.movePrevious()}},{key:"moveNext",value:function(){var t=this.steps[this.currentStep+1];t?(this.overlay.highlight(t),this.currentStep+=1):this.reset()}},{key:"hasNextStep",value:function(){return!!this.steps[this.currentStep+1]}},{key:"hasPreviousStep",value:function(){return!!this.steps[this.currentStep-1]}},{key:"reset",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.currentStep=0,this.isActivated=!1,this.overlay.clear(t)}},{key:"hasHighlightedElement",value:function(){var t=this.overlay.getHighlightedElement();return t&&t.node}},{key:"getHighlightedElement",value:function(){return this.overlay.getHighlightedElement()}},{key:"getLastHighlightedElement",value:function(){return this.overlay.getLastHighlightedElement()}},{key:"defineSteps",value:function(t){this.steps=[];for(var e=0;e<t.length;e++){var n=this.prepareElementFromStep(t[e],t,e);n&&this.steps.push(n)}}},{key:"prepareElementFromStep",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,o=B({},this.options),i=t,r="string"!=typeof t&&!v(t);if(!t||r&&!t.element)throw new Error("Element is required in step ".concat(n));r&&(i=t.element,o=B({},this.options,t));var s=v(i)?i:this.document.querySelector(i);if(!s)return console.warn("Element to highlight ".concat(i," not found")),null;var a=null;if(o.popover&&o.popover.title){var c=[this.options.className,o.popover.className].filter(function(t){return t}).join(" "),u=B({},o,o.popover,{className:c,totalCount:e.length,currentIndex:n,isFirst:0===n,isLast:0===e.length||n===e.length-1});a=new j(u,this.window,this.document)}var l=B({},o),h=new H(l,this.window,this.document);return new x({node:s,options:o,popover:a,stage:h,overlay:this.overlay,window:this.window,document:this.document})}},{key:"start",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;if(!this.steps||0===this.steps.length)throw new Error("There are no steps defined to iterate");this.isActivated=!0,this.currentStep=t,this.overlay.highlight(this.steps[t])}},{key:"highlight",value:function(t){this.isActivated=!0;var e=this.prepareElementFromStep(t);e&&this.overlay.highlight(e)}}])&&I(e.prototype,n),u&&I(e,u),t}()}]).default});
2
- //# sourceMappingURL=driver.min.js.map
 
 
 
dist/driver.min.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"driver.min.js","sources":["webpack://Driver/webpack/universalModuleDefinition"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Driver\"] = factory();\n\telse\n\t\troot[\"Driver\"] = factory();\n})(window, function() {\nreturn "],"mappings":"AAAA","sourceRoot":""}
 
 
dts-bundle-generator.config.ts ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ entries: [
3
+ {
4
+ filePath: "./src/index.ts",
5
+ outFile: `./dist/driver.js.d.ts`,
6
+ noCheck: false,
7
+ },
8
+ ],
9
+ };
favicon.svg ADDED
index.html ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Vite App</title>
8
+
9
+ <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
17
+ Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
18
+ font-size: 14px;
19
+ -webkit-font-smoothing: antialiased;
20
+ -moz-osx-font-smoothing: grayscale;
21
+ }
22
+
23
+ .container {
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ justify-content: center;
28
+ height: 100vh;
29
+ }
30
+
31
+ h1 {
32
+ margin: 40px 0 10px;
33
+ font-size: 48px;
34
+ font-weight: 600;
35
+ text-align: center;
36
+ }
37
+
38
+ h1 sup {
39
+ font-size: 18px;
40
+ font-weight: 400;
41
+ }
42
+
43
+ ul {
44
+ list-style: none;
45
+ padding: 0;
46
+ margin: 20px 10px 0;
47
+ line-height: 1.5;
48
+ }
49
+
50
+ ul li:before {
51
+ content: "•";
52
+ margin-right: 10px;
53
+ }
54
+ </style>
55
+ </head>
56
+ <body>
57
+ <div class="container">
58
+ <h1>driver.js <sup>next</sup></h1>
59
+ <p>Rewritten and enhanced version of driver.js</p>
60
+
61
+ <ul>
62
+ <li>Written in TypeScript</li>
63
+ <li>Lightweight — only 5kb gzipped</li>
64
+ <li>No dependencies</li>
65
+ <li>MIT Licensed</li>
66
+ </ul>
67
+ </div>
68
+ <script type="module">
69
+ import { driver } from "./src/driver.ts";
70
+
71
+ const driverObj = driver();
72
+
73
+ window.setTimeout(() => {
74
+ driverObj.highlight({
75
+ element: "h1",
76
+ popover: {
77
+ title: "Welcome to driver.js!",
78
+ description: "It's a rewritten version of driver.js",
79
+ position: "bottom",
80
+ },
81
+ });
82
+ }, 1000);
83
+
84
+ window.setTimeout(() => {
85
+ driverObj.highlight({
86
+ element: "p",
87
+ popover: {
88
+ title: "Welcome to driver.js!",
89
+ description: "It's a rewritten version of driver.js",
90
+ position: "bottom",
91
+ },
92
+ });
93
+ }, 2000);
94
+
95
+ window.setTimeout(() => {
96
+ driverObj.highlight({
97
+ element: "ul",
98
+ popover: {
99
+ title: "Welcome to driver.js!",
100
+ description: "It's a rewritten version of driver.js",
101
+ position: "bottom",
102
+ },
103
+ });
104
+ }, 3000);
105
+ </script>
106
+ </body>
107
+ </html>
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -1,54 +1,51 @@
1
  {
2
- "name": "driver.js",
3
- "version": "0.9.8",
4
- "description": "A light-weight, no-dependency, vanilla JavaScript library to drive the user's focus across the page",
5
- "main": "dist/driver.min.js",
6
- "types": "types/index.d.ts",
7
- "scripts": {
8
- "start": "node server.js",
9
- "build-demo": "NODE_ENV=production webpack --config config/webpack.config.demo.js",
10
- "build": "webpack --config config/webpack.config.prod.js",
11
- "deploy-demo": "NODE_DEBUG=gh-pages gh-pages -d dist/demo"
12
  },
13
- "bugs": {
14
- "url": "https://github.com/kamranahmedse/driver.js/issues"
 
 
 
 
 
 
 
 
 
 
15
  },
16
- "homepage": "https://github.com/kamranahmedse/driver.js#readme",
17
- "repository": "https://github.com/kamranahmedse/driver.js",
18
- "author": "Kamran Ahmed <[email protected]>",
19
- "license": "MIT",
20
  "devDependencies": {
21
- "@babel/core": "^7.4.5",
22
- "@babel/plugin-proposal-object-rest-spread": "^7.4.4",
23
- "@babel/preset-env": "^7.4.5",
24
- "autoprefixer": "^9.7.4",
25
- "babel-eslint": "^10.0.1",
26
- "babel-loader": "^8.0.6",
27
- "copy-webpack-plugin": "^5.0.3",
28
- "css-loader": "^3.0.0",
29
- "cssnano": "^4.1.10",
30
- "eslint": "^5.16.0",
31
- "eslint-config-airbnb-base": "^13.1.0",
32
- "eslint-loader": "^2.1.2",
33
- "eslint-plugin-import": "^2.17.3",
34
- "eslint-plugin-node": "^9.1.0",
35
- "extract-loader": "^3.1.0",
36
- "extract-text-webpack-plugin": "next",
37
- "file-loader": "^4.0.0",
38
- "gh-pages": "^2.0.1",
39
- "html-webpack-plugin": "^3.2.0",
40
- "node-sass": "^4.12.0",
41
- "opn": "^6.0.0",
42
- "optimize-css-assets-webpack-plugin": "^5.0.1",
43
- "postcss-loader": "^3.0.0",
44
- "sass-loader": "^7.1.0",
45
- "style-loader": "^0.23.1",
46
- "webpack": "^4.34.0",
47
- "webpack-cli": "^3.3.4",
48
- "webpack-dev-server": "^3.7.1"
49
- },
50
- "dependencies": {},
51
- "browserslist": [
52
- "defaults"
53
- ]
54
  }
 
1
  {
2
+ "name": "vite-vanilla-ts-lib-starter",
3
+ "private": true,
4
+ "version": "0.0.2",
5
+ "main": "./dist/vite-ts-lib-starter.cjs",
6
+ "module": "./dist/vite-ts-lib-starter.mjs",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./dist/vite-ts-lib-starter.cjs",
10
+ "import": "./dist/vite-ts-lib-starter.mjs"
11
+ }
12
  },
13
+ "scripts": {
14
+ "dev": "vite --host",
15
+ "build": "tsc && vite build && dts-bundle-generator --config ./dts-bundle-generator.config.ts",
16
+ "test": "vitest",
17
+ "test:coverage": "vitest --coverage",
18
+ "lint:scripts": "eslint . --ext .ts",
19
+ "lint:styles": "stylelint ./**/*.{css,scss}",
20
+ "format:scripts": "prettier . --write",
21
+ "format:styles": "stylelint ./**/*.{css,scss} --fix",
22
+ "format": "npm run format:scripts && npm run format:styles",
23
+ "prepare": "husky install && husky set .husky/pre-commit 'npx lint-staged' && git add .husky/pre-commit",
24
+ "uninstall-husky": "npm uninstall husky --no-save && git config --unset core.hooksPath && npx rimraf .husky"
25
  },
 
 
 
 
26
  "devDependencies": {
27
+ "@types/jsdom": "^21.1.1",
28
+ "@types/node": "^20.1.0",
29
+ "@typescript-eslint/eslint-plugin": "^5.59.2",
30
+ "@typescript-eslint/parser": "^5.59.2",
31
+ "@vitest/coverage-c8": "^0.31.0",
32
+ "dts-bundle-generator": "^8.0.1",
33
+ "eslint": "^8.40.0",
34
+ "eslint-config-prettier": "^8.8.0",
35
+ "eslint-plugin-prettier": "^4.2.1",
36
+ "husky": "^8.0.3",
37
+ "lint-staged": "^13.2.2",
38
+ "postcss": "^8.4.23",
39
+ "postcss-scss": "^4.0.6",
40
+ "prettier": "^2.8.8",
41
+ "stylelint": "^15.6.1",
42
+ "stylelint-config-prettier": "^9.0.5",
43
+ "stylelint-config-recommended": "^12.0.0",
44
+ "stylelint-config-sass-guidelines": "^10.0.0",
45
+ "stylelint-prettier": "^3.0.0",
46
+ "ts-node": "^10.9.1",
47
+ "typescript": "^5.0.4",
48
+ "vite": "^4.3.5",
49
+ "vitest": "^0.31.0"
50
+ }
 
 
 
 
 
 
 
 
 
51
  }
pnpm-lock.yaml ADDED
The diff for this file is too large to render. See raw diff
 
server.js DELETED
@@ -1,22 +0,0 @@
1
- const webpack = require('webpack');
2
- const WebpackDevServer = require('webpack-dev-server');
3
- const opn = require('opn');
4
-
5
- const config = require('./config/webpack.config.demo');
6
-
7
- const PORT = 3000;
8
- const HOST = 'localhost';
9
- const URL = `http://${HOST}:${PORT}`;
10
-
11
- config.entry.unshift(`webpack-dev-server/client?${URL}`);
12
-
13
- new WebpackDevServer(webpack(config))
14
- .listen(PORT, HOST, (error) => {
15
- if (error) {
16
- console.error(error);
17
- return;
18
- }
19
-
20
- opn(URL);
21
- console.log(`Listening at ${URL}`);
22
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/common/constants.js DELETED
@@ -1,52 +0,0 @@
1
- export const OVERLAY_OPACITY = 0.75;
2
- export const OVERLAY_PADDING = 10;
3
-
4
- export const SHOULD_ANIMATE_OVERLAY = true;
5
- export const SHOULD_OUTSIDE_CLICK_CLOSE = true;
6
- export const ALLOW_KEYBOARD_CONTROL = true;
7
- export const SHOULD_OUTSIDE_CLICK_NEXT = false;
8
-
9
- export const ESC_KEY_CODE = 27;
10
- export const LEFT_KEY_CODE = 37;
11
- export const RIGHT_KEY_CODE = 39;
12
-
13
- export const ID_OVERLAY = 'driver-page-overlay';
14
- export const ID_STAGE = 'driver-highlighted-element-stage';
15
- export const ID_POPOVER = 'driver-popover-item';
16
-
17
- export const CLASS_DRIVER_HIGHLIGHTED_ELEMENT = 'driver-highlighted-element';
18
- export const CLASS_POSITION_RELATIVE = 'driver-position-relative';
19
- export const CLASS_FIX_STACKING_CONTEXT = 'driver-fix-stacking';
20
-
21
- export const CLASS_STAGE_NO_ANIMATION = 'driver-stage-no-animation';
22
- export const CLASS_POPOVER_TIP = 'driver-popover-tip';
23
- export const CLASS_POPOVER_TITLE = 'driver-popover-title';
24
- export const CLASS_POPOVER_DESCRIPTION = 'driver-popover-description';
25
- export const CLASS_POPOVER_FOOTER = 'driver-popover-footer';
26
- export const CLASS_CLOSE_BTN = 'driver-close-btn';
27
- export const CLASS_NEXT_STEP_BTN = 'driver-next-btn';
28
- export const CLASS_PREV_STEP_BTN = 'driver-prev-btn';
29
- export const CLASS_BTN_DISABLED = 'driver-disabled';
30
- export const CLASS_CLOSE_ONLY_BTN = 'driver-close-only-btn';
31
- export const CLASS_NAVIGATION_BTNS = 'driver-navigation-btns';
32
-
33
- // NOTE: It must match the one set in the animations in CSS file
34
- export const ANIMATION_DURATION_MS = 300;
35
-
36
- // language=HTML
37
- export const POPOVER_HTML = (className = '') => `
38
- <div id="${ID_POPOVER}" class="${className}">
39
- <div class="${CLASS_POPOVER_TIP}"></div>
40
- <div class="${CLASS_POPOVER_TITLE}">Popover Title</div>
41
- <div class="${CLASS_POPOVER_DESCRIPTION}">Popover Description</div>
42
- <div class="driver-clearfix ${CLASS_POPOVER_FOOTER}">
43
- <button class="${CLASS_CLOSE_BTN}">Close</button>
44
- <span class="driver-btn-group ${CLASS_NAVIGATION_BTNS}">
45
- <button class="${CLASS_PREV_STEP_BTN}">&larr; Previous</button>
46
- <button class="${CLASS_NEXT_STEP_BTN}">Next &rarr;</button>
47
- </span>
48
- </div>
49
- </div>`;
50
-
51
- export const OVERLAY_HTML = `<div id="${ID_OVERLAY}"></div>`;
52
- export const STAGE_HTML = `<div id="${ID_STAGE}"></div>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/common/utils.js DELETED
@@ -1,56 +0,0 @@
1
- /**
2
- * Turn a string into a node
3
- * @param {String} htmlString to convert
4
- * @return {HTMLElement|Node} Converted node element
5
- */
6
- export const createNodeFromString = (htmlString) => {
7
- const div = document.createElement('div');
8
- div.innerHTML = htmlString.trim();
9
-
10
- // Change this to div.childNodes to support multiple top-level nodes
11
- return div.firstChild;
12
- };
13
-
14
- /**
15
- * Gets the CSS property from the given element
16
- * @param {HTMLElement|Node} element
17
- * @param {string} propertyName
18
- * @param {boolean} prefixVendor
19
- * @return {string}
20
- */
21
- export const getStyleProperty = (element, propertyName, prefixVendor = false) => {
22
- if (prefixVendor) {
23
- const prefixes = ['', '-webkit-', '-ms-', 'moz-', '-o-'];
24
- for (let counter = 0; counter < prefixes.length; counter++) {
25
- const prefixedProperty = prefixes[counter] + propertyName;
26
- const foundValue = getStyleProperty(element, prefixedProperty);
27
-
28
- if (foundValue) {
29
- return foundValue;
30
- }
31
- }
32
-
33
- return '';
34
- }
35
-
36
- let propertyValue = '';
37
-
38
- if (element.currentStyle) {
39
- propertyValue = element.currentStyle[propertyName];
40
- } else if (document.defaultView && document.defaultView.getComputedStyle) {
41
- propertyValue = document.defaultView
42
- .getComputedStyle(element, null)
43
- .getPropertyValue(propertyName);
44
- }
45
-
46
- return propertyValue && propertyValue.toLowerCase ? propertyValue.toLowerCase() : propertyValue;
47
- };
48
-
49
- /**
50
- * Checks if the passed element is dom object or not
51
- * @param element
52
- * @returns {boolean}
53
- */
54
- export const isDomElement = function (element) {
55
- return element && typeof element === 'object' && 'nodeType' in element;
56
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/core/element.js DELETED
@@ -1,392 +0,0 @@
1
- import {
2
- ANIMATION_DURATION_MS,
3
- CLASS_DRIVER_HIGHLIGHTED_ELEMENT,
4
- CLASS_FIX_STACKING_CONTEXT,
5
- CLASS_POSITION_RELATIVE,
6
- } from '../common/constants';
7
- import { getStyleProperty } from '../common/utils';
8
- import Position from './position';
9
-
10
- /**
11
- * Wrapper around DOMElements to enrich them
12
- * with the functionality necessary
13
- */
14
- export default class Element {
15
- /**
16
- * DOM element object
17
- * @param {Node|HTMLElement} node
18
- * @param {Object} options
19
- * @param {Popover} popover
20
- * @param {Stage} stage
21
- * @param {Overlay} overlay
22
- * @param {Window} window
23
- * @param {Document} document
24
- */
25
- constructor({
26
- node,
27
- options,
28
- popover,
29
- stage,
30
- overlay,
31
- window,
32
- document,
33
- } = {}) {
34
- this.node = node;
35
- this.document = document;
36
- this.window = window;
37
- this.options = options;
38
- this.overlay = overlay;
39
- this.popover = popover;
40
- this.stage = stage;
41
- this.animationTimeout = null;
42
- }
43
-
44
- /**
45
- * Checks if the current element is visible in viewport
46
- * @returns {boolean}
47
- * @public
48
- */
49
- isInView() {
50
- let top = this.node.offsetTop;
51
- let left = this.node.offsetLeft;
52
- const width = this.node.offsetWidth;
53
- const height = this.node.offsetHeight;
54
-
55
- let el = this.node;
56
-
57
- while (el.offsetParent) {
58
- el = el.offsetParent;
59
- top += el.offsetTop;
60
- left += el.offsetLeft;
61
- }
62
-
63
- return (
64
- top >= this.window.pageYOffset
65
- && left >= this.window.pageXOffset
66
- && (top + height) <= (this.window.pageYOffset + this.window.innerHeight)
67
- && (left + width) <= (this.window.pageXOffset + this.window.innerWidth)
68
- );
69
- }
70
-
71
- /**
72
- * Manually scrolls to the position of element if `scrollIntoView` fails
73
- * @private
74
- */
75
- scrollManually() {
76
- const elementRect = this.node.getBoundingClientRect();
77
- const absoluteElementTop = elementRect.top + this.window.pageYOffset;
78
- const middle = absoluteElementTop - (this.window.innerHeight / 2);
79
-
80
- this.window.scrollTo(0, middle);
81
- }
82
-
83
- /**
84
- * Brings the element to middle of the view port if not in view
85
- * @public
86
- */
87
- bringInView() {
88
- // If the node is not there or already is in view
89
- if (!this.node || this.isInView()) {
90
- return;
91
- }
92
-
93
- // If browser does not support scrollIntoView
94
- if (!this.node.scrollIntoView) {
95
- this.scrollManually();
96
- return;
97
- }
98
-
99
- try {
100
- this.node.scrollIntoView(this.options.scrollIntoViewOptions || {
101
- behavior: 'instant',
102
- block: 'center',
103
- });
104
- } catch (e) {
105
- // `block` option is not allowed in older versions of firefox, scroll manually
106
- this.scrollManually();
107
- }
108
- }
109
-
110
- /**
111
- * Gets the calculated position on screen, around which
112
- * we need to draw
113
- * @public
114
- * @return {Position}
115
- */
116
- getCalculatedPosition() {
117
- const body = this.document.body;
118
- const documentElement = this.document.documentElement;
119
- const window = this.window;
120
-
121
- const scrollTop = this.window.pageYOffset || documentElement.scrollTop || body.scrollTop;
122
- const scrollLeft = window.pageXOffset || documentElement.scrollLeft || body.scrollLeft;
123
- const elementRect = this.node.getBoundingClientRect();
124
-
125
- return new Position({
126
- top: elementRect.top + scrollTop,
127
- left: elementRect.left + scrollLeft,
128
- right: elementRect.left + scrollLeft + elementRect.width,
129
- bottom: elementRect.top + scrollTop + elementRect.height,
130
- });
131
- }
132
-
133
- /**
134
- * Gets the popover for the current element if any
135
- * @returns {Popover|*}
136
- * @public
137
- */
138
- getPopover() {
139
- return this.popover;
140
- }
141
-
142
- /**
143
- * Is called when element is about to be deselected
144
- * i.e. when moving the focus to next element of closing
145
- * @public
146
- */
147
- onDeselected(hideStage = false) {
148
- this.hidePopover();
149
-
150
- if (hideStage) {
151
- this.hideStage();
152
- }
153
-
154
- this.removeHighlightClasses();
155
-
156
- // If there was any animation in progress, cancel that
157
- this.window.clearTimeout(this.animationTimeout);
158
-
159
- if (this.options.onDeselected) {
160
- this.options.onDeselected(this);
161
- }
162
- }
163
-
164
- /**
165
- * Checks if the given element is same as the current element
166
- * @param {Element} element
167
- * @returns {boolean}
168
- * @public
169
- */
170
- isSame(element) {
171
- if (!element || !element.node) {
172
- return false;
173
- }
174
-
175
- return element.node === this.node;
176
- }
177
-
178
- /**
179
- * Is called when the element is about to be highlighted
180
- * @public
181
- */
182
- onHighlightStarted() {
183
- if (this.options.onHighlightStarted) {
184
- this.options.onHighlightStarted(this);
185
- }
186
- }
187
-
188
- /**
189
- * Is called when the element has been successfully highlighted
190
- * @public
191
- */
192
- onHighlighted() {
193
- const highlightedElement = this;
194
- if (!highlightedElement.isInView()) {
195
- highlightedElement.bringInView();
196
- }
197
-
198
- // Show the popover and stage once the item has been
199
- // brought in the view, this would allow us to handle
200
- // the cases where the container has scroll overflow
201
- this.showPopover();
202
- this.showStage();
203
- this.addHighlightClasses();
204
-
205
- if (this.options.onHighlighted) {
206
- this.options.onHighlighted(this);
207
- }
208
- }
209
-
210
- /**
211
- * Removes the stacking context fix classes and the highlighter classes
212
- * @private
213
- */
214
- removeHighlightClasses() {
215
- this.node.classList.remove(CLASS_DRIVER_HIGHLIGHTED_ELEMENT);
216
- this.node.classList.remove(CLASS_POSITION_RELATIVE);
217
-
218
- const stackFixes = this.document.querySelectorAll(`.${CLASS_FIX_STACKING_CONTEXT}`);
219
- for (let counter = 0; counter < stackFixes.length; counter++) {
220
- stackFixes[counter].classList.remove(CLASS_FIX_STACKING_CONTEXT);
221
- }
222
- }
223
-
224
- /**
225
- * Adds the highlight class on the current element and "fixes"
226
- * the parent nodes if they
227
- * @private
228
- */
229
- addHighlightClasses() {
230
- this.node.classList.add(CLASS_DRIVER_HIGHLIGHTED_ELEMENT);
231
-
232
- // Don't make relative if element already has some position set
233
- if (this.canMakeRelative()) {
234
- this.node.classList.add(CLASS_POSITION_RELATIVE);
235
- }
236
-
237
- // Check and re-define the stacking context
238
- this.fixStackingContext();
239
- }
240
-
241
- /**
242
- * Walks through the parents of the current element and fixes
243
- * the stacking context
244
- * @private
245
- */
246
- fixStackingContext() {
247
- let parentNode = this.node.parentNode;
248
- while (parentNode) {
249
- if (!parentNode.tagName || parentNode.tagName.toLowerCase() === 'body') {
250
- break;
251
- }
252
-
253
- const zIndex = getStyleProperty(parentNode, 'z-index');
254
- const opacity = parseFloat(getStyleProperty(parentNode, 'opacity'));
255
- const transform = getStyleProperty(parentNode, 'transform', true);
256
- const transformStyle = getStyleProperty(parentNode, 'transform-style', true);
257
- const transformBox = getStyleProperty(parentNode, 'transform-box', true);
258
- const filter = getStyleProperty(parentNode, 'filter', true);
259
- const perspective = getStyleProperty(parentNode, 'perspective', true);
260
-
261
- // Stacking context gets disturbed if
262
- // - Parent has z-index
263
- // - Opacity is below 0
264
- // - Filter/transform or perspective is applied
265
- if (
266
- /[0-9]+/.test(zIndex)
267
- || opacity < 1
268
- || (transform && transform !== 'none')
269
- || (transformStyle && transformStyle !== 'flat')
270
- || (transformBox && transformBox !== 'border-box')
271
- || (filter && filter !== 'none')
272
- || (perspective && perspective !== 'none')
273
- ) {
274
- parentNode.classList.add(CLASS_FIX_STACKING_CONTEXT);
275
- }
276
-
277
- parentNode = parentNode.parentNode;
278
- }
279
- }
280
-
281
- /**
282
- * Checks if we can make the current element relative or not
283
- * @return {boolean}
284
- * @private
285
- */
286
- canMakeRelative() {
287
- const currentPosition = this.getStyleProperty('position');
288
- const avoidPositionsList = ['absolute', 'fixed', 'relative'];
289
-
290
- // Because if the element has any of these positions, making it
291
- // relative will break the UI
292
- return avoidPositionsList.indexOf(currentPosition) === -1;
293
- }
294
-
295
- /**
296
- * Get current element's CSS attribute value
297
- * @param {string} property
298
- * @returns string
299
- * @private
300
- */
301
- getStyleProperty(property) {
302
- return getStyleProperty(this.node, property);
303
- }
304
-
305
- /**
306
- * Shows the stage behind the element
307
- * @public
308
- */
309
- showStage() {
310
- this.stage.show(this.getCalculatedPosition());
311
- }
312
-
313
- /**
314
- * Gets the DOM Element behind this element
315
- * @returns {Node|HTMLElement|*}
316
- * @public
317
- */
318
- getNode() {
319
- return this.node;
320
- }
321
-
322
- /**
323
- * Hides the stage
324
- * @public
325
- */
326
- hideStage() {
327
- this.stage.hide();
328
- }
329
-
330
- /**
331
- * Hides the popover if possible
332
- * @public
333
- */
334
- hidePopover() {
335
- if (!this.popover) {
336
- return;
337
- }
338
-
339
- this.popover.hide();
340
- }
341
-
342
- /**
343
- * Shows the popover on the current element
344
- * @public
345
- */
346
- showPopover() {
347
- if (!this.popover) {
348
- return;
349
- }
350
-
351
- const showAtPosition = this.getCalculatedPosition();
352
-
353
- // For first highlight, show it immediately because there won't be any animation
354
- let showAfterMs = ANIMATION_DURATION_MS;
355
- // If animation is disabled or if it is the first display, show it immediately
356
- if (!this.options.animate || !this.overlay.lastHighlightedElement) {
357
- showAfterMs = 0;
358
- }
359
-
360
- // @todo remove timeout and handle with CSS
361
- this.animationTimeout = this.window.setTimeout(() => {
362
- this.popover.show(showAtPosition);
363
- }, showAfterMs);
364
- }
365
-
366
- /**
367
- * @returns {{height: number, width: number}}
368
- * @public
369
- */
370
- getFullPageSize() {
371
- // eslint-disable-next-line prefer-destructuring
372
- const body = this.document.body;
373
- const html = this.document.documentElement;
374
-
375
- return {
376
- height: Math.max(body.scrollHeight, body.offsetHeight, html.scrollHeight, html.offsetHeight),
377
- width: Math.max(body.scrollWidth, body.offsetWidth, html.scrollWidth, html.offsetWidth),
378
- };
379
- }
380
-
381
- /**
382
- * Gets the size for popover
383
- * @returns {{height: number, width: number}}
384
- * @public
385
- */
386
- getSize() {
387
- return {
388
- height: Math.max(this.node.scrollHeight, this.node.offsetHeight),
389
- width: Math.max(this.node.scrollWidth, this.node.offsetWidth),
390
- };
391
- }
392
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/core/overlay.js DELETED
@@ -1,195 +0,0 @@
1
- import { ANIMATION_DURATION_MS, ID_OVERLAY, OVERLAY_HTML } from '../common/constants';
2
- import { createNodeFromString } from '../common/utils';
3
-
4
- /**
5
- * Responsible for overlay creation and manipulation i.e.
6
- * cutting out the visible part, animating between the sections etc
7
- */
8
- export default class Overlay {
9
- /**
10
- * @param {Object} options
11
- * @param {Window} window
12
- * @param {Document} document
13
- */
14
- constructor(options, window, document) {
15
- this.options = options;
16
-
17
- this.highlightedElement = null; // currently highlighted dom element (instance of Element)
18
- this.lastHighlightedElement = null; // element that was highlighted before current one
19
- this.hideTimer = null;
20
-
21
- this.window = window;
22
- this.document = document;
23
-
24
- this.removeNode = this.removeNode.bind(this);
25
- }
26
-
27
- /**
28
- * Prepares the overlay
29
- * @private
30
- */
31
- attachNode() {
32
- let pageOverlay = this.document.getElementById(ID_OVERLAY);
33
- if (!pageOverlay) {
34
- pageOverlay = createNodeFromString(OVERLAY_HTML);
35
- document.body.appendChild(pageOverlay);
36
- }
37
-
38
- this.node = pageOverlay;
39
- this.node.style.opacity = '0';
40
-
41
- if (!this.options.animate) {
42
- // For non-animation cases remove the overlay because we achieve this overlay by having
43
- // a higher box-shadow on the stage. Why are we doing it that way? Because the stage that
44
- // is shown "behind" the highlighted element to make it pop out of the screen, it introduces
45
- // some stacking contexts issues. To avoid those issues we just make the stage background
46
- // transparent and achieve the overlay using the shadow so to make the element below it visible
47
- // through the stage even if there are stacking issues.
48
- if (this.node.parentElement) {
49
- this.node.parentElement.removeChild(this.node);
50
- }
51
- }
52
- }
53
-
54
- /**
55
- * Highlights the dom element on the screen
56
- * @param {Element} element
57
- * @public
58
- */
59
- highlight(element) {
60
- if (!element || !element.node) {
61
- console.warn('Invalid element to highlight. Must be an instance of `Element`');
62
- return;
63
- }
64
-
65
- // If highlighted element is not changed from last time
66
- if (element.isSame(this.highlightedElement)) {
67
- return;
68
- }
69
-
70
- // There might be hide timer from last time
71
- // which might be getting triggered
72
- this.window.clearTimeout(this.hideTimer);
73
-
74
- // Trigger the hook for highlight started
75
- element.onHighlightStarted();
76
-
77
- // Old element has been deselected
78
- if (this.highlightedElement && !this.highlightedElement.isSame(this.lastHighlightedElement)) {
79
- this.highlightedElement.onDeselected();
80
- }
81
-
82
- // get the position of element around which we need to draw
83
- const position = element.getCalculatedPosition();
84
- if (!position.canHighlight()) {
85
- return;
86
- }
87
-
88
- this.lastHighlightedElement = this.highlightedElement;
89
- this.highlightedElement = element;
90
-
91
- this.show();
92
-
93
- // Element has been highlighted
94
- this.highlightedElement.onHighlighted();
95
- }
96
-
97
- /**
98
- * Shows the overlay on whole screen
99
- * @public
100
- */
101
- show() {
102
- if (this.node && this.node.parentElement) {
103
- return;
104
- }
105
-
106
- this.attachNode();
107
-
108
- window.setTimeout(() => {
109
- this.node.style.opacity = `${this.options.opacity}`;
110
- this.node.style.position = 'fixed';
111
- this.node.style.left = '0';
112
- this.node.style.top = '0';
113
- this.node.style.bottom = '0';
114
- this.node.style.right = '0';
115
- });
116
- }
117
-
118
- /**
119
- * Returns the currently selected element
120
- * @returns {null|*}
121
- * @public
122
- */
123
- getHighlightedElement() {
124
- return this.highlightedElement;
125
- }
126
-
127
- /**
128
- * Gets the element that was highlighted before current element
129
- * @returns {null|*}
130
- * @public
131
- */
132
- getLastHighlightedElement() {
133
- return this.lastHighlightedElement;
134
- }
135
-
136
- /**
137
- * Removes the overlay and cancel any listeners
138
- * @public
139
- */
140
- clear(immediate = false) {
141
- // Callback for when overlay is about to be reset
142
- if (this.options.onReset) {
143
- this.options.onReset(this.highlightedElement);
144
- }
145
-
146
- // Deselect the highlighted element if any
147
- if (this.highlightedElement) {
148
- const hideStage = true;
149
- this.highlightedElement.onDeselected(hideStage);
150
- }
151
-
152
- this.highlightedElement = null;
153
- this.lastHighlightedElement = null;
154
-
155
- if (!this.node) {
156
- return;
157
- }
158
-
159
- // Clear any existing timers and remove node
160
- this.window.clearTimeout(this.hideTimer);
161
-
162
- if (this.options.animate && !immediate) {
163
- this.node.style.opacity = '0';
164
- this.hideTimer = this.window.setTimeout(this.removeNode, ANIMATION_DURATION_MS);
165
- } else {
166
- this.removeNode();
167
- }
168
- }
169
-
170
- /**
171
- * Removes the overlay node if it exists
172
- * @private
173
- */
174
- removeNode() {
175
- if (this.node && this.node.parentElement) {
176
- this.node.parentElement.removeChild(this.node);
177
- }
178
- }
179
-
180
- /**
181
- * Refreshes the overlay i.e. sets the size according to current window size
182
- * And moves the highlight around if necessary
183
- * @public
184
- */
185
- refresh() {
186
- // If no highlighted element, cancel the refresh
187
- if (!this.highlightedElement) {
188
- return;
189
- }
190
-
191
- // Reposition the stage and show popover
192
- this.highlightedElement.showPopover();
193
- this.highlightedElement.showStage();
194
- }
195
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/core/popover.js DELETED
@@ -1,509 +0,0 @@
1
- import Element from './element';
2
- import {
3
- CLASS_BTN_DISABLED,
4
- CLASS_CLOSE_BTN,
5
- CLASS_CLOSE_ONLY_BTN,
6
- CLASS_NEXT_STEP_BTN,
7
- CLASS_POPOVER_DESCRIPTION,
8
- CLASS_POPOVER_FOOTER,
9
- CLASS_POPOVER_TIP,
10
- CLASS_POPOVER_TITLE,
11
- CLASS_PREV_STEP_BTN,
12
- ID_POPOVER,
13
- POPOVER_HTML,
14
- } from '../common/constants';
15
- import { createNodeFromString } from '../common/utils';
16
-
17
- /**
18
- * Popover that is displayed on top of the highlighted element
19
- */
20
- export default class Popover extends Element {
21
- /**
22
- * @param {Object} options
23
- * @param {Window} window
24
- * @param {Document} document
25
- */
26
- constructor(options, window, document) {
27
- super();
28
-
29
- this.options = {
30
- isFirst: true,
31
- isLast: true,
32
- totalCount: 1,
33
- currentIndex: 0,
34
- offset: 0,
35
- showButtons: true,
36
- closeBtnText: 'Close',
37
- doneBtnText: 'Done',
38
- startBtnText: 'Next &rarr;',
39
- nextBtnText: 'Next &rarr;',
40
- prevBtnText: '&larr; Previous',
41
- ...options,
42
- };
43
-
44
- this.window = window;
45
- this.document = document;
46
- }
47
-
48
- /**
49
- * Prepares the dom element for popover
50
- * @private
51
- */
52
- attachNode() {
53
- let popover = this.document.getElementById(ID_POPOVER);
54
- if (popover) {
55
- popover.parentElement.removeChild(popover);
56
- }
57
-
58
- popover = createNodeFromString(POPOVER_HTML(this.options.className));
59
- document.body.appendChild(popover);
60
-
61
- this.node = popover;
62
- this.tipNode = popover.querySelector(`.${CLASS_POPOVER_TIP}`);
63
- this.titleNode = popover.querySelector(`.${CLASS_POPOVER_TITLE}`);
64
- this.descriptionNode = popover.querySelector(`.${CLASS_POPOVER_DESCRIPTION}`);
65
- this.footerNode = popover.querySelector(`.${CLASS_POPOVER_FOOTER}`);
66
- this.nextBtnNode = popover.querySelector(`.${CLASS_NEXT_STEP_BTN}`);
67
- this.prevBtnNode = popover.querySelector(`.${CLASS_PREV_STEP_BTN}`);
68
- this.closeBtnNode = popover.querySelector(`.${CLASS_CLOSE_BTN}`);
69
- }
70
-
71
- /**
72
- * Gets the title node for the popover
73
- * @returns {Element | null | *}
74
- * @public
75
- */
76
- getTitleNode() {
77
- return this.titleNode;
78
- }
79
-
80
- /**
81
- * Gets the description node for the popover
82
- * @returns {Element | null | *}
83
- * @public
84
- */
85
- getDescriptionNode() {
86
- return this.descriptionNode;
87
- }
88
-
89
- /**
90
- * Hides the popover
91
- * @public
92
- */
93
- hide() {
94
- // If hide is called when the node isn't created yet
95
- if (!this.node) {
96
- return;
97
- }
98
-
99
- this.node.style.display = 'none';
100
- }
101
-
102
- /**
103
- * Sets the default state for the popover
104
- * @private
105
- */
106
- setInitialState() {
107
- this.node.style.display = 'block';
108
- this.node.style.left = '0';
109
- this.node.style.top = '0';
110
- this.node.style.bottom = '';
111
- this.node.style.right = '';
112
-
113
- // Remove the positional classes from tip
114
- this.node
115
- .querySelector(`.${CLASS_POPOVER_TIP}`)
116
- .className = CLASS_POPOVER_TIP;
117
- }
118
-
119
- /**
120
- * Shows the popover at the given position
121
- * @param {Position} position
122
- * @public
123
- */
124
- show(position) {
125
- this.attachNode();
126
- this.setInitialState();
127
-
128
- // Set the title and descriptions
129
- this.titleNode.innerHTML = this.options.title;
130
- this.descriptionNode.innerHTML = this.options.description || '';
131
-
132
- this.renderFooter();
133
-
134
- // Position the popover around the given position
135
- switch (this.options.position) {
136
- case 'left':
137
- case 'left-top':
138
- this.positionOnLeft(position);
139
- break;
140
- case 'left-center':
141
- this.positionOnLeftCenter(position);
142
- break;
143
- case 'left-bottom':
144
- this.positionOnLeftBottom(position);
145
- break;
146
- case 'right':
147
- case 'right-top':
148
- this.positionOnRight(position);
149
- break;
150
- case 'right-center':
151
- this.positionOnRightCenter(position);
152
- break;
153
- case 'right-bottom':
154
- this.positionOnRightBottom(position);
155
- break;
156
- case 'top':
157
- case 'top-left':
158
- this.positionOnTop(position);
159
- break;
160
- case 'top-center':
161
- this.positionOnTopCenter(position);
162
- break;
163
- case 'top-right':
164
- this.positionOnTopRight(position);
165
- break;
166
- case 'bottom':
167
- case 'bottom-left':
168
- this.positionOnBottom(position);
169
- break;
170
- case 'bottom-center':
171
- this.positionOnBottomCenter(position);
172
- break;
173
- case 'bottom-right':
174
- this.positionOnBottomRight(position);
175
- break;
176
- case 'mid-center':
177
- this.positionOnMidCenter(position);
178
- break;
179
- case 'auto':
180
- default:
181
- this.autoPosition(position);
182
- break;
183
- }
184
-
185
- // Bring the popover in view port once it is displayed
186
- this.bringInView();
187
- }
188
-
189
- /**
190
- * Enables, disables buttons, sets the text and
191
- * decides if to show them or not
192
- * @private
193
- */
194
- renderFooter() {
195
- this.nextBtnNode.innerHTML = this.options.nextBtnText;
196
- this.prevBtnNode.innerHTML = this.options.prevBtnText;
197
- this.closeBtnNode.innerHTML = this.options.closeBtnText;
198
-
199
- const hasSteps = this.options.totalCount && this.options.totalCount !== 1;
200
-
201
- // If there was only one item, hide the buttons
202
- if (!this.options.showButtons) {
203
- this.footerNode.style.display = 'none';
204
- return;
205
- }
206
-
207
- // If this is just a single highlighted element i.e. there
208
- // are no other steps to go to – just hide the navigation buttons
209
- if (!hasSteps) {
210
- this.nextBtnNode.style.display = 'none';
211
- this.prevBtnNode.style.display = 'none';
212
- this.closeBtnNode.classList.add(CLASS_CLOSE_ONLY_BTN);
213
- } else {
214
- // @todo modify CSS to use block
215
- this.nextBtnNode.style.display = 'inline-block';
216
- this.prevBtnNode.style.display = 'inline-block';
217
- this.closeBtnNode.classList.remove(CLASS_CLOSE_ONLY_BTN);
218
- }
219
-
220
- this.footerNode.style.display = 'block';
221
- if (this.options.isFirst) {
222
- this.prevBtnNode.classList.add(CLASS_BTN_DISABLED);
223
- this.nextBtnNode.innerHTML = this.options.startBtnText;
224
- } else {
225
- this.prevBtnNode.classList.remove(CLASS_BTN_DISABLED);
226
- }
227
-
228
- if (this.options.isLast) {
229
- this.nextBtnNode.innerHTML = this.options.doneBtnText;
230
- } else {
231
- this.nextBtnNode.innerHTML = this.options.nextBtnText;
232
- }
233
- }
234
-
235
- /**
236
- * Shows the popover on the left of the given position
237
- * @param {Position} elementPosition
238
- * @private
239
- */
240
- positionOnLeft(elementPosition) {
241
- const popoverWidth = this.getSize().width;
242
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
243
-
244
- this.node.style.left = `${elementPosition.left - popoverWidth - popoverMargin}px`;
245
- this.node.style.top = `${(elementPosition.top + this.options.offset) - this.options.padding}px`;
246
- this.node.style.right = '';
247
- this.node.style.bottom = '';
248
-
249
- this.tipNode.classList.add('right');
250
- }
251
-
252
- /**
253
- * Shows the popover on the left of the given position
254
- * @param {Position} elementPosition
255
- * @private
256
- */
257
- positionOnLeftBottom(elementPosition) {
258
- const popoverDimensions = this.getSize();
259
-
260
- const popoverWidth = popoverDimensions.width;
261
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
262
-
263
- this.node.style.left = `${elementPosition.left - popoverWidth - popoverMargin}px`;
264
- this.node.style.top = `${(elementPosition.bottom + this.options.padding + this.options.offset) - popoverDimensions.height}px`;
265
- this.node.style.bottom = '';
266
- this.node.style.right = '';
267
-
268
- this.tipNode.classList.add('right', 'position-bottom');
269
- }
270
-
271
- /**
272
- * Shows the popover on the left center of the given position
273
- * @param {Position} elementPosition
274
- * @private
275
- */
276
- positionOnLeftCenter(elementPosition) {
277
- const popoverDimensions = this.getSize();
278
-
279
- const popoverWidth = popoverDimensions.width;
280
- const popoverHeight = popoverDimensions.height;
281
- const popoverCenter = popoverHeight / 2;
282
-
283
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
284
- const elementCenter = (elementPosition.bottom - elementPosition.top) / 2;
285
- const topCenterPosition = (elementPosition.top - popoverCenter) + elementCenter + this.options.offset;
286
-
287
- this.node.style.left = `${elementPosition.left - popoverWidth - popoverMargin}px`;
288
- this.node.style.top = `${topCenterPosition}px`;
289
- this.node.style.right = '';
290
- this.node.style.bottom = '';
291
-
292
- this.tipNode.classList.add('right', 'position-center');
293
- }
294
-
295
- /**
296
- * Shows the popover on the right of the given position
297
- * @param {Position} elementPosition
298
- * @private
299
- */
300
- positionOnRight(elementPosition) {
301
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
302
-
303
- this.node.style.left = `${elementPosition.right + popoverMargin}px`;
304
- this.node.style.top = `${(elementPosition.top + this.options.offset) - this.options.padding}px`;
305
- this.node.style.right = '';
306
- this.node.style.bottom = '';
307
-
308
- this.tipNode.classList.add('left');
309
- }
310
-
311
- /**
312
- * Shows the popover on the right of the given position
313
- * @param {Position} elementPosition
314
- * @private
315
- */
316
- positionOnRightCenter(elementPosition) {
317
- const popoverDimensions = this.getSize();
318
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
319
-
320
- const popoverHeight = popoverDimensions.height;
321
- const popoverCenter = popoverHeight / 2;
322
- const elementCenter = (elementPosition.bottom - elementPosition.top) / 2;
323
- const topCenterPosition = (elementPosition.top - popoverCenter) + elementCenter + this.options.offset;
324
-
325
- this.node.style.left = `${elementPosition.right + popoverMargin}px`;
326
- this.node.style.top = `${topCenterPosition}px`;
327
- this.node.style.right = '';
328
- this.node.style.bottom = '';
329
-
330
- this.tipNode.classList.add('left', 'position-center');
331
- }
332
-
333
- /**
334
- * Shows the popover on the right of the given position
335
- * @param {Position} elementPosition
336
- * @private
337
- */
338
- positionOnRightBottom(elementPosition) {
339
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
340
- const popoverDimensions = this.getSize();
341
-
342
- this.node.style.left = `${elementPosition.right + popoverMargin}px`;
343
- this.node.style.top = `${(elementPosition.bottom + this.options.padding + this.options.offset) - popoverDimensions.height}px`;
344
- this.node.style.bottom = '';
345
- this.node.style.right = '';
346
-
347
- this.tipNode.classList.add('left', 'position-bottom');
348
- }
349
-
350
- /**
351
- * Shows the popover on the top of the given position
352
- * @param {Position} elementPosition
353
- * @private
354
- */
355
- positionOnTop(elementPosition) {
356
- const popoverHeight = this.getSize().height;
357
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
358
-
359
- this.node.style.top = `${elementPosition.top - popoverHeight - popoverMargin}px`;
360
- this.node.style.left = `${(elementPosition.left - this.options.padding) + this.options.offset}px`;
361
- this.node.style.right = '';
362
- this.node.style.bottom = '';
363
-
364
- this.tipNode.classList.add('bottom');
365
- }
366
-
367
- /**
368
- * Shows the popover on the top center of the given position
369
- * @param {Position} elementPosition
370
- * @private
371
- */
372
- positionOnTopCenter(elementPosition) {
373
- const dimensions = this.getSize();
374
- const popoverHeight = dimensions.height;
375
- const popoverWidth = dimensions.width / 2;
376
-
377
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
378
- const nodeCenter = this.options.offset + elementPosition.left + ((elementPosition.right - elementPosition.left) / 2);
379
-
380
- this.node.style.top = `${elementPosition.top - popoverHeight - popoverMargin}px`;
381
- this.node.style.left = `${nodeCenter - popoverWidth - this.options.padding}px`;
382
- this.node.style.right = '';
383
- this.node.style.bottom = '';
384
-
385
- // Add the tip at the top center
386
- this.tipNode.classList.add('bottom', 'position-center');
387
- }
388
-
389
- /**
390
- * Shows the popover on the top right of the given position
391
- * @param {Position} elementPosition
392
- * @private
393
- */
394
- positionOnTopRight(elementPosition) {
395
- const dimensions = this.getSize();
396
- const popoverHeight = dimensions.height;
397
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
398
-
399
- this.node.style.top = `${elementPosition.top - popoverHeight - popoverMargin}px`;
400
- this.node.style.left = `${(elementPosition.right + this.options.padding + this.options.offset) - dimensions.width}px`;
401
- this.node.style.right = '';
402
- this.node.style.bottom = '';
403
-
404
- // Add the tip at the top center
405
- this.tipNode.classList.add('bottom', 'position-right');
406
- }
407
-
408
- /**
409
- * Shows the popover on the bottom of the given position
410
- * @param {Position} elementPosition
411
- * @private
412
- */
413
- positionOnBottom(elementPosition) {
414
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
415
-
416
- this.node.style.top = `${elementPosition.bottom + popoverMargin}px`;
417
- this.node.style.left = `${(elementPosition.left - this.options.padding) + this.options.offset}px`;
418
- this.node.style.right = '';
419
- this.node.style.bottom = '';
420
-
421
- this.tipNode.classList.add('top');
422
- }
423
-
424
- /**
425
- * Shows the popover on the bottom-center of the given position
426
- * @param {Position} elementPosition
427
- * @private
428
- */
429
- positionOnBottomCenter(elementPosition) {
430
- const popoverWidth = this.getSize().width / 2;
431
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
432
- const nodeCenter = this.options.offset + elementPosition.left + ((elementPosition.right - elementPosition.left) / 2);
433
-
434
- this.node.style.top = `${elementPosition.bottom + popoverMargin}px`;
435
- this.node.style.left = `${nodeCenter - popoverWidth - this.options.padding}px`;
436
- this.node.style.right = '';
437
- this.node.style.bottom = '';
438
-
439
- // Add the tip at the top center
440
- this.tipNode.classList.add('top', 'position-center');
441
- }
442
-
443
- /**
444
- * Shows the popover on the bottom-right of the given position
445
- * @param {Position} elementPosition
446
- * @private
447
- */
448
- positionOnBottomRight(elementPosition) {
449
- const dimensions = this.getSize();
450
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
451
-
452
- this.node.style.top = `${elementPosition.bottom + popoverMargin}px`;
453
- this.node.style.left = `${(elementPosition.right + this.options.padding + this.options.offset) - dimensions.width}px`;
454
- this.node.style.right = '';
455
- this.node.style.bottom = '';
456
-
457
- // Add the tip at the top center
458
- this.tipNode.classList.add('top', 'position-right');
459
- }
460
-
461
- /**
462
- * Shows the popover on the mid-center of the given position
463
- * @param {Position} elementPosition
464
- * @private
465
- */
466
- positionOnMidCenter(elementPosition) {
467
- const popoverDimensions = this.getSize();
468
- const popoverHeight = popoverDimensions.height;
469
- const popoverWidth = popoverDimensions.width / 2;
470
- const popoverCenter = popoverHeight / 2;
471
-
472
- const elementCenter = (elementPosition.bottom - elementPosition.top) / 2;
473
- const topCenterPosition = (elementPosition.top - popoverCenter) + elementCenter + this.options.offset;
474
- const nodeCenter = this.options.offset + elementPosition.left + ((elementPosition.right - elementPosition.left) / 2);
475
-
476
- this.node.style.top = `${topCenterPosition}px`;
477
- this.node.style.left = `${nodeCenter - popoverWidth - this.options.padding}px`;
478
- this.node.style.right = '';
479
- this.node.style.bottom = '';
480
-
481
- // Add the tip at the top center
482
- this.tipNode.classList.add('mid-center');
483
- }
484
-
485
- /**
486
- * Automatically positions the popover around the given position
487
- * such that the element and popover remain in view
488
- * @todo add the left and right positioning decisions
489
- * @param {Position} elementPosition
490
- * @private
491
- */
492
- autoPosition(elementPosition) {
493
- const pageSize = this.getFullPageSize();
494
- const popoverSize = this.getSize();
495
-
496
- const pageHeight = pageSize.height;
497
- const popoverHeight = popoverSize.height;
498
- const popoverMargin = this.options.padding + 10; // adding 10 to give it a little distance from the element
499
-
500
- const pageHeightAfterPopOver = elementPosition.bottom + popoverHeight + popoverMargin;
501
-
502
- // If adding popover would go out of the window height, then show it to the top
503
- if (pageHeightAfterPopOver >= pageHeight) {
504
- this.positionOnTop(elementPosition);
505
- } else {
506
- this.positionOnBottom(elementPosition);
507
- }
508
- }
509
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/core/position.js DELETED
@@ -1,32 +0,0 @@
1
- /**
2
- * Responsible for validating positions and is used
3
- * when manipulating positions across the application
4
- */
5
- export default class Position {
6
- /**
7
- * @param {number} left
8
- * @param {number} top
9
- * @param {number} right
10
- * @param {number} bottom
11
- */
12
- constructor({
13
- left = 0,
14
- top = 0,
15
- right = 0,
16
- bottom = 0,
17
- } = {}) {
18
- this.left = left;
19
- this.right = right;
20
- this.top = top;
21
- this.bottom = bottom;
22
- }
23
-
24
- /**
25
- * Checks if the position is valid to be highlighted
26
- * @returns {boolean}
27
- * @public
28
- */
29
- canHighlight() {
30
- return this.left < this.right && this.top < this.bottom;
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/core/stage.js DELETED
@@ -1,92 +0,0 @@
1
- import { CLASS_STAGE_NO_ANIMATION, ID_STAGE, STAGE_HTML } from '../common/constants';
2
- import { createNodeFromString } from '../common/utils';
3
- import Element from './element';
4
-
5
- /**
6
- * Stage behind the highlighted element to give it a little
7
- * highlight from rest of the page
8
- */
9
- export default class Stage extends Element {
10
- /**
11
- * @param {Object} options
12
- * @param {Window} window
13
- * @param {Document} document
14
- */
15
- constructor(options, window, document) {
16
- super();
17
-
18
- this.options = options;
19
- this.window = window;
20
- this.document = document;
21
- }
22
-
23
- /**
24
- * Prepares the DOM element if not already there
25
- * @private
26
- */
27
- attachNode() {
28
- let stage = this.document.getElementById(ID_STAGE);
29
- if (!stage) {
30
- stage = createNodeFromString(STAGE_HTML);
31
- document.body.appendChild(stage);
32
- }
33
-
34
- this.node = stage;
35
-
36
- if (!this.options.animate) {
37
- this.node.classList.add(CLASS_STAGE_NO_ANIMATION);
38
- } else {
39
- this.node.classList.remove(CLASS_STAGE_NO_ANIMATION);
40
- }
41
- }
42
-
43
- /**
44
- * Simply hides the stage
45
- * @public
46
- */
47
- hide() {
48
- if (!this.node || !this.node.parentElement) {
49
- return;
50
- }
51
-
52
- this.node.parentElement.removeChild(this.node);
53
- }
54
-
55
- /**
56
- * Makes it visible and sets the default properties
57
- * @private
58
- */
59
- setInitialStyle() {
60
- this.node.style.display = 'block';
61
- this.node.style.left = '0';
62
- this.node.style.top = '0';
63
- this.node.style.bottom = '';
64
- this.node.style.right = '';
65
- }
66
-
67
- /**
68
- * Shows the stage at provided position
69
- * @param {Position} position
70
- * @public
71
- */
72
- show(position) {
73
- this.attachNode();
74
-
75
- this.setInitialStyle();
76
-
77
- // Make it two times the padding because, half will be given on left and half on right
78
- const requiredPadding = this.options.padding * 2;
79
-
80
- const width = (position.right - position.left) + (requiredPadding);
81
- const height = (position.bottom - position.top) + (requiredPadding);
82
-
83
- // Show the stage
84
- this.node.style.display = 'block';
85
- this.node.style.position = 'absolute';
86
- this.node.style.width = `${width}px`;
87
- this.node.style.height = `${height}px`;
88
- this.node.style.top = `${position.top - (requiredPadding / 2)}px`;
89
- this.node.style.left = `${position.left - (requiredPadding / 2)}px`;
90
- this.node.style.backgroundColor = this.options.stageBackground;
91
- }
92
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/driver.scss DELETED
@@ -1,234 +0,0 @@
1
- $text-color: #2d2d2d !default;
2
- $popover-bg: #ffffff !default;
3
- $stage-bg: #ffffff !default;
4
- $button-bg: #f1f1f1 !default;
5
- $disabled-btn-color: #808080 !default;
6
-
7
- $popover-z-index: 1000000000 !default;
8
- $overlay-z-index: 100002 !default;
9
- $stage-z-index: 100003 !default;
10
- $highlighted-element-z-index: 100004 !default;
11
-
12
- // Note: If you update this duration, make sure to
13
- // update `ANIMATION_DURATION_MS` constant
14
- $animation-ms: 300 !default;
15
- $animation-sec: ($animation-ms / 1000) * 1s !default;
16
-
17
- div#driver-popover-item {
18
- display: none;
19
- position: absolute;
20
- background: $popover-bg;
21
- color: $text-color;
22
- margin: 0;
23
- padding: 15px;
24
- border-radius: 5px;
25
- min-width: 250px;
26
- max-width: 300px;
27
- box-shadow: 0 1px 10px rgba(0, 0, 0, 0.4);
28
- z-index: $popover-z-index;
29
-
30
- .driver-popover-tip {
31
- border: 5px solid $popover-bg;
32
- content: '';
33
- position: absolute;
34
-
35
- &.bottom {
36
- bottom: -10px;
37
- border-top-color: $popover-bg;
38
- border-right-color: transparent;
39
- border-bottom-color: transparent;
40
- border-left-color: transparent;
41
-
42
- &.position-center {
43
- left: 49%;
44
- }
45
-
46
- &.position-right {
47
- right: 20px;
48
- }
49
- }
50
-
51
- &.left {
52
- left: -10px;
53
- top: 10px;
54
- border-top-color: transparent;
55
- border-right-color: $popover-bg;
56
- border-bottom-color: transparent;
57
- border-left-color: transparent;
58
-
59
- &.position-center {
60
- top: 46%;
61
- }
62
-
63
- &.position-bottom {
64
- top: auto;
65
- bottom: 20px;
66
- }
67
- }
68
-
69
- &.right {
70
- right: -10px;
71
- top: 10px;
72
- border-top-color: transparent;
73
- border-right-color: transparent;
74
- border-bottom-color: transparent;
75
- border-left-color: $popover-bg;
76
-
77
- &.position-center {
78
- top: 46%;
79
- }
80
-
81
- &.position-bottom {
82
- top: auto;
83
- bottom: 20px;
84
- }
85
- }
86
-
87
- &.top {
88
- top: -10px;
89
- border-top-color: transparent;
90
- border-right-color: transparent;
91
- border-bottom-color: $popover-bg;
92
- border-left-color: transparent;
93
-
94
- &.position-center {
95
- left: 49%;
96
- }
97
-
98
- &.position-right {
99
- right: 20px;
100
- }
101
- }
102
-
103
- &.mid-center {
104
- display: none;
105
- }
106
- }
107
-
108
- .driver-popover-footer {
109
- display: block;
110
- margin-top: 10px;
111
-
112
- button {
113
- display: inline-block;
114
- padding: 3px 10px;
115
- border: 1px solid #d4d4d4;
116
- text-decoration: none;
117
- text-shadow: 1px 1px 0 #fff;
118
- color: $text-color;
119
- font: 11px/normal sans-serif;
120
- cursor: pointer;
121
- outline: 0;
122
- background-color: $button-bg;
123
- border-radius: 2px;
124
- zoom: 1;
125
- line-height: 1.3;
126
- }
127
-
128
- button.driver-disabled {
129
- color: $disabled-btn-color;
130
- cursor: default;
131
- pointer-events: none;
132
- }
133
-
134
- .driver-close-btn {
135
- float: left;
136
- }
137
-
138
- .driver-close-only-btn {
139
- float: right;
140
- }
141
-
142
- .driver-btn-group {
143
- float: right;
144
- }
145
- }
146
-
147
- .driver-popover-title {
148
- font: 19px/normal sans-serif;
149
- margin: 0 0 5px;
150
- font-weight: bold;
151
- display: block;
152
- position: relative;
153
- line-height: 1.5;
154
- zoom: 1;
155
- }
156
-
157
- .driver-popover-description {
158
- margin-bottom: 0;
159
- font: 14px/normal sans-serif;
160
- line-height: 1.5;
161
- color: $text-color;
162
- font-weight: normal;
163
- zoom: 1;
164
- }
165
- }
166
-
167
- .driver-clearfix:before {
168
- content: "";
169
- display: table;
170
- }
171
-
172
- .driver-clearfix:after {
173
- clear: both;
174
- content: "";
175
- display: table;
176
- }
177
-
178
- .driver-stage-no-animation {
179
- transition: none !important;
180
-
181
- background: transparent !important;
182
- outline: 5000px solid rgba(0, 0, 0, 0.75);
183
- }
184
-
185
- div#driver-page-overlay {
186
- background: #000000;
187
- position: fixed;
188
- top: 0;
189
- left: 0;
190
- bottom: 0;
191
- right: 0;
192
- display: block;
193
- width: 100%;
194
- height: 100%;
195
- zoom: 1;
196
- filter: alpha(opacity=75);
197
- opacity: 0.75;
198
- z-index: $overlay-z-index !important;
199
-
200
- transition: all $animation-sec;
201
- }
202
-
203
- div#driver-highlighted-element-stage {
204
- position: absolute;
205
- top: 0;
206
- left: 0;
207
- height: 50px;
208
- width: 300px;
209
- background: $stage-bg;
210
- z-index: $stage-z-index !important;
211
- display: none;
212
- border-radius: 2px;
213
-
214
- transition: all $animation-sec;
215
- }
216
-
217
- .driver-highlighted-element {
218
- z-index: $highlighted-element-z-index !important;
219
- }
220
-
221
- .driver-position-relative {
222
- position: relative !important;
223
- }
224
-
225
- .driver-fix-stacking {
226
- z-index: auto !important;
227
- opacity: 1.0 !important;
228
- transform: none !important;
229
- filter: none !important;
230
- perspective: none !important;
231
- transform-style: flat !important;
232
- transform-box: border-box !important;
233
- will-change: unset !important;
234
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/driver.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { initEvents, destroyEvents } from "./events";
2
+ import { destroyHighlight, highlight } from "./highlight";
3
+ import { destroyStage } from "./stage";
4
+
5
+ export type DriveStep = {
6
+ element?: string | Element;
7
+ popover: {
8
+ title: string;
9
+ description: string;
10
+ position: "top" | "bottom" | "left" | "right";
11
+ };
12
+ };
13
+
14
+ export function driver() {
15
+ function init() {
16
+ document.body.classList.add("driver-active");
17
+
18
+ initEvents();
19
+ }
20
+
21
+ function destroy() {
22
+ document.body.classList.remove("driver-active");
23
+
24
+ destroyEvents();
25
+ destroyHighlight();
26
+ destroyStage();
27
+ }
28
+
29
+ return {
30
+ drive: (steps: DriveStep[]) => console.log(steps),
31
+ highlight: (step: DriveStep) => {
32
+ init();
33
+ highlight(step);
34
+ },
35
+ destroy,
36
+ };
37
+ }
src/events.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { refreshActiveHighlight } from "./highlight";
2
+
3
+ let resizeTimeout: number;
4
+
5
+ function onResize() {
6
+ if (resizeTimeout) {
7
+ window.cancelAnimationFrame(resizeTimeout);
8
+ }
9
+
10
+ resizeTimeout = window.requestAnimationFrame(refreshActiveHighlight);
11
+ }
12
+
13
+ export function initEvents() {
14
+ window.addEventListener("resize", onResize);
15
+ }
16
+
17
+ export function destroyEvents() {
18
+ window.removeEventListener("resize", onResize);
19
+ }
src/highlight.ts ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { DriveStep } from "./driver";
2
+ import { refreshStage, trackActiveElement, transitionStage } from "./stage";
3
+
4
+ let previousHighlight: Element | undefined;
5
+ let activeHighlight: Element | undefined;
6
+ let isTransitioning = false;
7
+
8
+ export function highlight(step: DriveStep) {
9
+ const { element } = step;
10
+ const elemObj =
11
+ typeof element === "string" ? document.querySelector(element) : element;
12
+
13
+ if (!elemObj) {
14
+ return;
15
+ }
16
+
17
+ previousHighlight = activeHighlight;
18
+ activeHighlight = elemObj;
19
+
20
+ transferHighlight(previousHighlight || elemObj, elemObj);
21
+ }
22
+
23
+ export function refreshActiveHighlight() {
24
+ if (!activeHighlight) {
25
+ return;
26
+ }
27
+
28
+ trackActiveElement(activeHighlight);
29
+ refreshStage();
30
+ }
31
+
32
+ function transferHighlight(from: Element, to: Element) {
33
+ const duration = 400;
34
+ const start = Date.now();
35
+ isTransitioning = true;
36
+
37
+ const animate = () => {
38
+ if (!isTransitioning) {
39
+ return;
40
+ }
41
+
42
+ const elapsed = Date.now() - start;
43
+
44
+ if (elapsed < duration) {
45
+ transitionStage(elapsed, duration, from, to);
46
+ } else {
47
+ trackActiveElement(to);
48
+
49
+ isTransitioning = false;
50
+ }
51
+
52
+ refreshStage();
53
+ window.requestAnimationFrame(animate);
54
+ };
55
+
56
+ window.requestAnimationFrame(animate);
57
+
58
+ from.classList.remove("driver-active-element");
59
+ to.classList.add("driver-active-element");
60
+
61
+ isTransitioning = true;
62
+ }
63
+
64
+ export function destroyHighlight() {
65
+ activeHighlight = undefined;
66
+ isTransitioning = false;
67
+ previousHighlight = undefined;
68
+ activeHighlight = undefined;
69
+
70
+ document.querySelectorAll(".driver-active-element").forEach(element => {
71
+ element.classList.remove("driver-active-element");
72
+ });
73
+ }
src/index.js DELETED
@@ -1,458 +0,0 @@
1
- import Overlay from './core/overlay';
2
- import Element from './core/element';
3
- import Popover from './core/popover';
4
- import {
5
- CLASS_CLOSE_BTN,
6
- CLASS_NEXT_STEP_BTN,
7
- CLASS_PREV_STEP_BTN,
8
- ESC_KEY_CODE,
9
- ID_POPOVER,
10
- LEFT_KEY_CODE,
11
- OVERLAY_OPACITY,
12
- OVERLAY_PADDING,
13
- RIGHT_KEY_CODE,
14
- SHOULD_ANIMATE_OVERLAY,
15
- SHOULD_OUTSIDE_CLICK_CLOSE,
16
- SHOULD_OUTSIDE_CLICK_NEXT,
17
- ALLOW_KEYBOARD_CONTROL,
18
- } from './common/constants';
19
- import Stage from './core/stage';
20
- import { isDomElement } from './common/utils';
21
-
22
- /**
23
- * Plugin class that drives the plugin
24
- */
25
- export default class Driver {
26
- /**
27
- * @param {Object} options
28
- */
29
- constructor(options = {}) {
30
- this.options = {
31
- animate: SHOULD_ANIMATE_OVERLAY, // Whether to animate or not
32
- opacity: OVERLAY_OPACITY, // Overlay opacity
33
- padding: OVERLAY_PADDING, // Spacing around the element from the overlay
34
- scrollIntoViewOptions: null, // Options to be passed to `scrollIntoView`
35
- allowClose: SHOULD_OUTSIDE_CLICK_CLOSE, // Whether to close overlay on click outside the element
36
- keyboardControl: ALLOW_KEYBOARD_CONTROL, // Whether to allow controlling through keyboard or not
37
- overlayClickNext: SHOULD_OUTSIDE_CLICK_NEXT, // Whether to move next on click outside the element
38
- stageBackground: '#ffffff', // Background color for the stage
39
- onHighlightStarted: () => null, // When element is about to be highlighted
40
- onHighlighted: () => null, // When element has been highlighted
41
- onDeselected: () => null, // When the element has been deselected
42
- onReset: () => null, // When overlay is about to be cleared
43
- onNext: () => null, // When next button is clicked
44
- onPrevious: () => null, // When previous button is clicked
45
- ...options,
46
- };
47
-
48
- this.document = document;
49
- this.window = window;
50
- this.isActivated = false;
51
- this.steps = []; // steps to be presented if any
52
- this.currentStep = 0; // index for the currently highlighted step
53
- this.currentMovePrevented = false; // If the current move was prevented
54
-
55
- this.overlay = new Overlay(this.options, window, document);
56
-
57
- this.onResize = this.onResize.bind(this);
58
- this.onKeyUp = this.onKeyUp.bind(this);
59
- this.onClick = this.onClick.bind(this);
60
- this.moveNext = this.moveNext.bind(this);
61
- this.movePrevious = this.movePrevious.bind(this);
62
- this.preventMove = this.preventMove.bind(this);
63
-
64
- // Event bindings
65
- this.bind();
66
- }
67
-
68
- /**
69
- * Getter for steps property
70
- * @readonly
71
- * @public
72
- */
73
- getSteps() {
74
- return this.steps;
75
- }
76
-
77
- /**
78
- * Setter for steps property
79
- * @param steps
80
- * @public
81
- */
82
- setSteps(steps) {
83
- this.steps = steps;
84
- }
85
-
86
- /**
87
- * Binds any DOM events listeners
88
- * @todo: add throttling in all the listeners
89
- * @private
90
- */
91
- bind() {
92
- this.window.addEventListener('resize', this.onResize, false);
93
- this.window.addEventListener('keyup', this.onKeyUp, false);
94
-
95
- // Binding both touch and click results in popup getting shown and then immediately get hidden.
96
- // Adding the check to not bind the click event if the touch is supported i.e. on mobile devices
97
- // Issue: https://github.com/kamranahmedse/driver.js/issues/150
98
- if (!('ontouchstart' in document.documentElement)) {
99
- this.window.addEventListener('click', this.onClick, false);
100
- } else {
101
- this.window.addEventListener('touchstart', this.onClick, false);
102
- }
103
- }
104
-
105
- /**
106
- * Removes the popover if clicked outside the highlighted element
107
- * or outside the
108
- * @param e
109
- * @private
110
- */
111
- onClick(e) {
112
- if (!this.isActivated || !this.hasHighlightedElement()) {
113
- return;
114
- }
115
-
116
- // Stop the event propagation on click/tap. `onClick` handles
117
- // both touch and click events – which on some browsers causes
118
- // the click to close the tour
119
- e.stopPropagation();
120
-
121
- const highlightedElement = this.overlay.getHighlightedElement();
122
- const popover = this.document.getElementById(ID_POPOVER);
123
-
124
- const clickedHighlightedElement = highlightedElement.node.contains(e.target);
125
- const clickedPopover = popover && popover.contains(e.target);
126
-
127
- // Perform the 'Next' operation when clicked outside the highlighted element
128
- if (!clickedHighlightedElement && !clickedPopover && this.options.overlayClickNext) {
129
- this.handleNext();
130
- return;
131
- }
132
-
133
- // Remove the overlay If clicked outside the highlighted element
134
- if (!clickedHighlightedElement && !clickedPopover && this.options.allowClose) {
135
- this.reset();
136
- return;
137
- }
138
-
139
- const nextClicked = e.target.classList.contains(CLASS_NEXT_STEP_BTN);
140
- const prevClicked = e.target.classList.contains(CLASS_PREV_STEP_BTN);
141
- const closeClicked = e.target.classList.contains(CLASS_CLOSE_BTN);
142
-
143
- if (closeClicked) {
144
- this.reset();
145
- return;
146
- }
147
-
148
- if (nextClicked) {
149
- this.handleNext();
150
- } else if (prevClicked) {
151
- this.handlePrevious();
152
- }
153
- }
154
-
155
- /**
156
- * Handler for the onResize DOM event
157
- * Makes sure highlighted element stays at valid position
158
- * @private
159
- */
160
- onResize() {
161
- if (!this.isActivated) {
162
- return;
163
- }
164
-
165
- this.refresh();
166
- }
167
-
168
- /**
169
- * Refreshes and repositions the popover and the overlay
170
- */
171
- refresh() {
172
- this.overlay.refresh();
173
- }
174
-
175
- /**
176
- * Clears the overlay on escape key process
177
- * @param event
178
- * @private
179
- */
180
- onKeyUp(event) {
181
- // If driver is not active or keyboard control is disabled
182
- if (!this.isActivated || !this.options.keyboardControl) {
183
- return;
184
- }
185
-
186
- // If escape was pressed and it is allowed to click outside to close
187
- if (event.keyCode === ESC_KEY_CODE && this.options.allowClose) {
188
- this.reset();
189
- return;
190
- }
191
-
192
- // If there is no highlighted element or there is a highlighted element
193
- // without popover or if the popover does not allow buttons - ignore
194
- const highlightedElement = this.getHighlightedElement();
195
- if (!highlightedElement || !highlightedElement.popover) {
196
- return;
197
- }
198
-
199
- if (event.keyCode === RIGHT_KEY_CODE) {
200
- this.handleNext();
201
- } else if (event.keyCode === LEFT_KEY_CODE) {
202
- this.handlePrevious();
203
- }
204
- }
205
-
206
- /**
207
- * Moves to the previous step if possible
208
- * otherwise resets the overlay
209
- * @public
210
- */
211
- movePrevious() {
212
- const previousStep = this.steps[this.currentStep - 1];
213
- if (!previousStep) {
214
- this.reset();
215
- return;
216
- }
217
-
218
- this.overlay.highlight(previousStep);
219
- this.currentStep -= 1;
220
- }
221
-
222
- /**
223
- * Prevents the current move. Useful in `onNext` if you want to
224
- * perform some asynchronous task and manually move to next step
225
- * @public
226
- */
227
- preventMove() {
228
- this.currentMovePrevented = true;
229
- }
230
-
231
- /**
232
- * Handles the internal "move to next" event
233
- * @private
234
- */
235
- handleNext() {
236
- this.currentMovePrevented = false;
237
-
238
- // Call the bound `onNext` handler if available
239
- const currentStep = this.steps[this.currentStep];
240
- if (currentStep && currentStep.options && currentStep.options.onNext) {
241
- currentStep.options.onNext(this.overlay.highlightedElement);
242
- }
243
-
244
- if (this.currentMovePrevented) {
245
- return;
246
- }
247
-
248
- this.moveNext();
249
- }
250
-
251
- /**
252
- * Handles the internal "move to previous" event
253
- * @private
254
- */
255
- handlePrevious() {
256
- this.currentMovePrevented = false;
257
-
258
- // Call the bound `onPrevious` handler if available
259
- const currentStep = this.steps[this.currentStep];
260
- if (currentStep && currentStep.options && currentStep.options.onPrevious) {
261
- currentStep.options.onPrevious(this.overlay.highlightedElement);
262
- }
263
-
264
- if (this.currentMovePrevented) {
265
- return;
266
- }
267
-
268
- this.movePrevious();
269
- }
270
-
271
- /**
272
- * Moves to the next step if possible
273
- * otherwise resets the overlay
274
- * @public
275
- */
276
- moveNext() {
277
- const nextStep = this.steps[this.currentStep + 1];
278
- if (!nextStep) {
279
- this.reset();
280
- return;
281
- }
282
-
283
- this.overlay.highlight(nextStep);
284
- this.currentStep += 1;
285
- }
286
-
287
- /**
288
- * @returns {boolean}
289
- * @public
290
- */
291
- hasNextStep() {
292
- return !!this.steps[this.currentStep + 1];
293
- }
294
-
295
- /**
296
- * @returns {boolean}
297
- * @public
298
- */
299
- hasPreviousStep() {
300
- return !!this.steps[this.currentStep - 1];
301
- }
302
-
303
- /**
304
- * Resets the steps if any and clears the overlay
305
- * @param {boolean} immediate
306
- * @public
307
- */
308
- reset(immediate = false) {
309
- this.currentStep = 0;
310
- this.isActivated = false;
311
- this.overlay.clear(immediate);
312
- }
313
-
314
- /**
315
- * Checks if there is any highlighted element or not
316
- * @returns {boolean}
317
- * @public
318
- */
319
- hasHighlightedElement() {
320
- const highlightedElement = this.overlay.getHighlightedElement();
321
- return highlightedElement && highlightedElement.node;
322
- }
323
-
324
- /**
325
- * Gets the currently highlighted element in overlay
326
- * @returns {Element}
327
- * @public
328
- */
329
- getHighlightedElement() {
330
- return this.overlay.getHighlightedElement();
331
- }
332
-
333
- /**
334
- * Gets the element that was highlighted before currently highlighted element
335
- * @returns {Element}
336
- * @public
337
- */
338
- getLastHighlightedElement() {
339
- return this.overlay.getLastHighlightedElement();
340
- }
341
-
342
- /**
343
- * Defines steps to be highlighted
344
- * @param {array} steps
345
- * @public
346
- */
347
- defineSteps(steps) {
348
- this.steps = [];
349
-
350
- for (let counter = 0; counter < steps.length; counter++) {
351
- const element = this.prepareElementFromStep(steps[counter], steps, counter);
352
- if (!element) {
353
- continue;
354
- }
355
-
356
- this.steps.push(element);
357
- }
358
- }
359
-
360
- /**
361
- * Prepares the step received from the user and returns an instance
362
- * of Element
363
- *
364
- * @param currentStep Step that is being prepared
365
- * @param allSteps List of all the steps
366
- * @param index Index of the current step
367
- * @returns {null|Element}
368
- * @private
369
- */
370
- prepareElementFromStep(currentStep, allSteps = [], index = 0) {
371
- let elementOptions = { ...this.options };
372
- let querySelector = currentStep;
373
-
374
- // If the `currentStep` is step definition
375
- // then grab the options and element from the definition
376
- const isStepDefinition = typeof currentStep !== 'string' && !isDomElement(currentStep);
377
-
378
- if (!currentStep || (isStepDefinition && !currentStep.element)) {
379
- throw new Error(`Element is required in step ${index}`);
380
- }
381
-
382
- if (isStepDefinition) {
383
- querySelector = currentStep.element;
384
- elementOptions = { ...this.options, ...currentStep };
385
- }
386
-
387
- // If the given element is a query selector or a DOM element?
388
- const domElement = isDomElement(querySelector) ? querySelector : this.document.querySelector(querySelector);
389
- if (!domElement) {
390
- console.warn(`Element to highlight ${querySelector} not found`);
391
- return null;
392
- }
393
-
394
- let popover = null;
395
- if (elementOptions.popover && elementOptions.popover.title) {
396
- const mergedClassNames = [
397
- this.options.className,
398
- elementOptions.popover.className,
399
- ].filter(c => c).join(' ');
400
-
401
- const popoverOptions = {
402
- ...elementOptions,
403
- ...elementOptions.popover,
404
- className: mergedClassNames,
405
- totalCount: allSteps.length,
406
- currentIndex: index,
407
- isFirst: index === 0,
408
- isLast: allSteps.length === 0 || index === allSteps.length - 1, // Only one item or last item
409
- };
410
-
411
- popover = new Popover(popoverOptions, this.window, this.document);
412
- }
413
-
414
- const stageOptions = { ...elementOptions };
415
- const stage = new Stage(stageOptions, this.window, this.document);
416
-
417
- return new Element({
418
- node: domElement,
419
- options: elementOptions,
420
- popover,
421
- stage,
422
- overlay: this.overlay,
423
- window: this.window,
424
- document: this.document,
425
- });
426
- }
427
-
428
- /**
429
- * Initiates highlighting steps from first step
430
- * @param {number} index at which highlight is to be started
431
- * @public
432
- */
433
- start(index = 0) {
434
- if (!this.steps || this.steps.length === 0) {
435
- throw new Error('There are no steps defined to iterate');
436
- }
437
-
438
- this.isActivated = true;
439
- this.currentStep = index;
440
- this.overlay.highlight(this.steps[index]);
441
- }
442
-
443
- /**
444
- * Highlights the given element
445
- * @param {string|{element: string, popover: {}}} selector Query selector or a step definition
446
- * @public
447
- */
448
- highlight(selector) {
449
- this.isActivated = true;
450
-
451
- const element = this.prepareElementFromStep(selector);
452
- if (!element) {
453
- return;
454
- }
455
-
456
- this.overlay.highlight(element);
457
- }
458
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/math.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { easeInOutQuad } from "./math";
2
+
3
+ export type StageDefinition = {
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ };
9
+
10
+ let activeStagePosition: StageDefinition | undefined;
11
+ let stageSvg: SVGSVGElement | undefined;
12
+
13
+ // This method calculates the animated new position of the
14
+ // stage (called for each frame by requestAnimationFrame)
15
+ export function transitionStage(
16
+ elapsed: number,
17
+ duration: number,
18
+ from: Element,
19
+ to: Element
20
+ ) {
21
+ const fromDefinition = activeStagePosition
22
+ ? activeStagePosition
23
+ : from.getBoundingClientRect();
24
+
25
+ const toDefinition = to.getBoundingClientRect();
26
+
27
+ const x = easeInOutQuad(
28
+ elapsed,
29
+ fromDefinition.x,
30
+ toDefinition.x - fromDefinition.x,
31
+ duration
32
+ );
33
+
34
+ const y = easeInOutQuad(
35
+ elapsed,
36
+ fromDefinition.y,
37
+ toDefinition.y - fromDefinition.y,
38
+ duration
39
+ );
40
+
41
+ const width = easeInOutQuad(
42
+ elapsed,
43
+ fromDefinition.width,
44
+ toDefinition.width - fromDefinition.width,
45
+ duration
46
+ );
47
+
48
+ const height = easeInOutQuad(
49
+ elapsed,
50
+ fromDefinition.height,
51
+ toDefinition.height - fromDefinition.height,
52
+ duration
53
+ );
54
+
55
+ activeStagePosition = {
56
+ x,
57
+ y,
58
+ width,
59
+ height,
60
+ };
61
+
62
+ renderStage(activeStagePosition);
63
+ }
64
+
65
+ export function trackActiveElement(element: Element) {
66
+ if (!element) {
67
+ return;
68
+ }
69
+
70
+ const definition = element.getBoundingClientRect();
71
+
72
+ activeStagePosition = {
73
+ x: definition.x,
74
+ y: definition.y,
75
+ width: definition.width,
76
+ height: definition.height,
77
+ };
78
+
79
+ renderStage(activeStagePosition);
80
+ }
81
+
82
+ export function refreshStage() {
83
+ if (!activeStagePosition) {
84
+ return;
85
+ }
86
+
87
+ if (!stageSvg) {
88
+ console.warn("No stage svg found.");
89
+ return;
90
+ }
91
+
92
+ const windowX = window.innerWidth;
93
+ const windowY = window.innerHeight;
94
+
95
+ stageSvg.setAttribute("viewBox", `0 0 ${windowX} ${windowY}`);
96
+ }
97
+
98
+ function renderStage(stagePosition: StageDefinition) {
99
+ if (!stageSvg) {
100
+ stageSvg = createStageSvg(stagePosition);
101
+ document.body.appendChild(stageSvg);
102
+
103
+ return;
104
+ }
105
+
106
+ const pathElement = stageSvg.firstElementChild as SVGPathElement | null;
107
+ if (pathElement?.tagName !== "path") {
108
+ throw new Error("no path element found in stage svg");
109
+ }
110
+
111
+ pathElement.setAttribute("d", generateSvgCutoutPathString(stagePosition));
112
+ }
113
+
114
+ function createStageSvg(stage: StageDefinition): SVGSVGElement {
115
+ const windowX = window.innerWidth;
116
+ const windowY = window.innerHeight;
117
+
118
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
119
+ svg.classList.add("driver-stage", "driver-stage-animated");
120
+
121
+ svg.setAttribute("viewBox", `0 0 ${windowX} ${windowY}`);
122
+ svg.setAttribute("xmlSpace", "preserve");
123
+ svg.setAttribute("xmlnsXlink", "http://www.w3.org/1999/xlink");
124
+ svg.setAttribute("version", "1.1");
125
+ svg.setAttribute("preserveAspectRatio", "xMinYMin slice");
126
+
127
+ svg.style.fillRule = "evenodd";
128
+ svg.style.clipRule = "evenodd";
129
+ svg.style.strokeLinejoin = "round";
130
+ svg.style.strokeMiterlimit = "2";
131
+ svg.style.zIndex = "10000";
132
+ svg.style.position = "fixed";
133
+ svg.style.top = "0";
134
+ svg.style.left = "0";
135
+ svg.style.width = "100%";
136
+ svg.style.height = "100%";
137
+
138
+ const cutoutPath = document.createElementNS(
139
+ "http://www.w3.org/2000/svg",
140
+ "path"
141
+ );
142
+
143
+ cutoutPath.setAttribute("d", generateSvgCutoutPathString(stage));
144
+
145
+ cutoutPath.style.fill = "rgb(0,0,0)";
146
+ cutoutPath.style.opacity = `0.7`;
147
+ cutoutPath.style.pointerEvents = "auto";
148
+ cutoutPath.style.cursor = "auto";
149
+
150
+ svg.appendChild(cutoutPath);
151
+
152
+ return svg;
153
+ }
154
+
155
+ function generateSvgCutoutPathString(stage: StageDefinition) {
156
+ const padding = 10;
157
+ const radius = 5;
158
+
159
+ const windowX = window.innerWidth;
160
+ const windowY = window.innerHeight;
161
+
162
+ const stageWidth = stage.width + padding * 2;
163
+ const stageHeight = stage.height + padding * 2;
164
+
165
+ // prevent glitches when stage is too small for radius
166
+ const limitedRadius = Math.min(radius, stageWidth / 2, stageHeight / 2);
167
+
168
+ // no value below 0 allowed + round down
169
+ const normalizedRadius = Math.floor(Math.max(limitedRadius, 0));
170
+
171
+ const highlightBoxX = stage.x - padding + normalizedRadius;
172
+ const highlightBoxY = stage.y - padding;
173
+ const highlightBoxWidth = stageWidth - normalizedRadius * 2;
174
+ const highlightBoxHeight = stageHeight - normalizedRadius * 2;
175
+
176
+ return `M${windowX},0L0,0L0,${windowY}L${windowX},${windowY}L${windowX},0Z
177
+ M${highlightBoxX},${highlightBoxY} h${highlightBoxWidth} a${normalizedRadius},${normalizedRadius} 0 0 1 ${normalizedRadius},${normalizedRadius} v${highlightBoxHeight} a${normalizedRadius},${normalizedRadius} 0 0 1 -${normalizedRadius},${normalizedRadius} h-${highlightBoxWidth} a${normalizedRadius},${normalizedRadius} 0 0 1 -${normalizedRadius},-${normalizedRadius} v-${highlightBoxHeight} a${normalizedRadius},${normalizedRadius} 0 0 1 ${normalizedRadius},-${normalizedRadius} z`;
178
+ }
179
+
180
+ export function destroyStage() {
181
+ if (stageSvg) {
182
+ stageSvg.remove();
183
+ stageSvg = undefined;
184
+ }
185
+
186
+ activeStagePosition = undefined;
187
+ }
src/style.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .driver-active .driver-stage {
2
+ pointer-events: none;
3
+ }
4
+
5
+ .driver-active * {
6
+ pointer-events: none;
7
+ }
8
+
9
+ .driver-active .driver-active-element,
10
+ .driver-active .driver-active-element * {
11
+ pointer-events: auto;
12
+ cursor: auto;
13
+ }