Add basic highlight functionality
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .babelrc +0 -14
- .editorconfig +0 -8
- .eslintignore +7 -0
- .eslintrc +18 -0
- .eslintrc.json +0 -22
- .gitignore +24 -6
- .husky/pre-commit +4 -0
- .lintstagedrc +4 -0
- .npmignore +0 -8
- .prettierignore +6 -0
- .prettierrc +16 -0
- .stylelintignore +7 -0
- .stylelintrc +21 -0
- config/webpack.config.demo.js +0 -96
- config/webpack.config.prod.js +0 -79
- demo/images/browserstack.png +0 -0
- demo/images/driver.png +0 -0
- demo/images/driver.svg +0 -195
- demo/images/favicon.png +0 -0
- demo/images/separator.png +0 -0
- demo/images/split.png +0 -0
- demo/index.html +0 -412
- demo/scripts/demo.js +0 -359
- demo/styles/base.scss +0 -154
- demo/styles/demo.scss +0 -129
- dist/driver.min.css +0 -1
- dist/driver.min.js +0 -2
- dist/driver.min.js.map +0 -1
- dts-bundle-generator.config.ts +9 -0
- favicon.svg +15 -0
- index.html +107 -0
- package-lock.json +0 -0
- package.json +46 -49
- pnpm-lock.yaml +0 -0
- server.js +0 -22
- src/common/constants.js +0 -52
- src/common/utils.js +0 -56
- src/core/element.js +0 -392
- src/core/overlay.js +0 -195
- src/core/popover.js +0 -509
- src/core/position.js +0 -32
- src/core/stage.js +0 -92
- src/driver.scss +0 -234
- src/driver.ts +37 -0
- src/events.ts +19 -0
- src/highlight.ts +73 -0
- src/index.js +0 -458
- src/math.ts +11 -0
- src/stage.ts +187 -0
- src/style.css +13 -0
.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 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
.idea
|
5 |
-
.
|
6 |
-
|
7 |
-
|
8 |
-
|
|
|
|
|
|
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: '<em>An italicized title</em>',
|
178 |
-
description: 'Description may also contain <strong>HTML</strong>'
|
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: '<em>An italicized title</em>',
|
199 |
-
description: 'Description may also contain <strong>HTML</strong>'
|
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 →",nextBtnText:"Next →",prevBtnText:"← 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",'">← Previous</button>\n <button class="').concat("driver-next-btn",'">Next →</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": "
|
3 |
-
"
|
4 |
-
"
|
5 |
-
"main": "dist/
|
6 |
-
"
|
7 |
-
"
|
8 |
-
"
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
},
|
13 |
-
"
|
14 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
"@
|
22 |
-
"@
|
23 |
-
"@
|
24 |
-
"
|
25 |
-
"
|
26 |
-
"
|
27 |
-
"
|
28 |
-
"
|
29 |
-
"
|
30 |
-
"
|
31 |
-
"
|
32 |
-
"
|
33 |
-
"
|
34 |
-
"
|
35 |
-
"
|
36 |
-
"
|
37 |
-
"
|
38 |
-
"
|
39 |
-
"
|
40 |
-
"node
|
41 |
-
"
|
42 |
-
"
|
43 |
-
"
|
44 |
-
|
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}">← Previous</button>
|
46 |
-
<button class="${CLASS_NEXT_STEP_BTN}">Next →</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 →',
|
39 |
-
nextBtnText: 'Next →',
|
40 |
-
prevBtnText: '← 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 |
+
}
|