Refactor stage padding and radius

This commit is contained in:
Kamran Ahmed
2023-06-11 02:49:32 +01:00
parent fd57e7f639
commit edd7dca2df
7 changed files with 594 additions and 3698 deletions
+136 -164
View File
@@ -12,8 +12,8 @@
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
"Helvetica Neue", sans-serif;
font-size: 14px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -121,7 +121,7 @@
<button id="dim-highlight-btn">Super Dim Highlight</button>
<button id="scrollable-area-btn">Scrollable Area</button>
<button id="inner-scroll-area-btn">Inner Scroll Area</button>
<button id="tour-btn">Start Tour</button>
<button id="without-element-btn">No Element</button>
<button id="destroy-btn">Destroy</button>
</div>
@@ -134,19 +134,15 @@
<h2>Yet another Tour Library?</h2>
<p>
No, it is not. Tours are just one of the many use-cases. Driver.js can
be used wherever you need some sort of overlay for the page; some common
usecases could be: e.g. dimming the background when user is interacting
with some component, using it as a focus shifter to bring user's
attention to some component on page, or using it to simulate those "Turn
off the Lights" widgets that you might have seen on video players
online, etc.
No, it is not. Tours are just one of the many use-cases. Driver.js can be used wherever you need some sort of
overlay for the page; some common usecases could be: e.g. dimming the background when user is interacting with
some component, using it as a focus shifter to bring user's attention to some component on page, or using it to
simulate those "Turn off the Lights" widgets that you might have seen on video players online, etc.
</p>
<p class="second-para">
Driver.js is written in Vanilla JS, has zero dependencies and is highly
customizable. It has several options allowing you to manipulate how it
behaves and also provides you the hooks to manipulate the elements as
they are highlighted, about to be highlighted, or deselected.
Driver.js is written in Vanilla JS, has zero dependencies and is highly customizable. It has several options
allowing you to manipulate how it behaves and also provides you the hooks to manipulate the elements as they are
highlighted, about to be highlighted, or deselected.
</p>
<h2 id="installation-head">Installation</h2>
@@ -157,120 +153,100 @@ yarn add driver.js
npm install driver.js</pre
>
<p>
Or include it using CDN — put the version as driver.js@0.5 in the name
</p>
<p>Or include it using CDN — put the version as driver.js@0.5 in the name</p>
<pre>https://unpkg.com/driver.js/dist/driver.min.js</pre>
<h2>Usage and Demo</h2>
<p id="large-paragraph-text">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates! Lorem ipsum dolor sit amet, consectetur
adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus
nesciunt non omnis, quasi recusandae tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates! Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea
eligendi id in inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<div id="scrollable-area">
<p>
First -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
First -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Second -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Second -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p id="third-scroll-paragraph">
Third -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Third -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Fourth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Fourth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Fifth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Fifth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Sixth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Sixth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Seventh -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Seventh -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Eighth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Eighth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
<p>
Ninth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Consequuntur dicta ipsum labore quod tempora ullam? Alias consequatur
doloremque laborum maxime necessitatibus nostrum odio, officiis
quibusdam veniam! Doloribus eos id quaerat.
Ninth -> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dicta ipsum labore quod
tempora ullam? Alias consequatur doloremque laborum maxime necessitatibus nostrum odio, officiis quibusdam
veniam! Doloribus eos id quaerat.
</p>
</div>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi
blanditiis consectetur ea eligendi id in inventore ipsa iure laudantium
libero, minus molestias necessitatibus nesciunt non omnis, quasi
recusandae tempore voluptates!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi blanditiis consectetur ea eligendi id in
inventore ipsa iure laudantium libero, minus molestias necessitatibus nesciunt non omnis, quasi recusandae
tempore voluptates!
</p>
</div>
<script type="module">
@@ -280,84 +256,80 @@ npm install driver.js</pre
driver({ animate: true }).highlight({ element: "h1" });
});
document
.getElementById("simple-highlight-btn")
.addEventListener("click", () => {
driver({ animate: false }).highlight({
element: "#large-paragraph-text",
popover: {
title: "driver.js",
description: "Highlight anything, anywhere on the page",
align: "end",
side: "top",
},
});
document.getElementById("simple-highlight-btn").addEventListener("click", () => {
driver({ animate: false }).highlight({
element: "#large-paragraph-text",
popover: {
title: "driver.js",
description: "Highlight anything, anywhere on the page",
align: "end",
side: "top",
},
});
});
document.getElementById("dark-highlight-btn").addEventListener("click", () => {
driver({
animate: true,
opacity: 0.9,
}).highlight({ element: "ul" });
});
document.getElementById("dim-highlight-btn").addEventListener("click", () => {
driver({
animate: true,
opacity: 0.2,
}).highlight({ element: ".buttons" });
});
document.getElementById("transition-highlight-btn").addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "h1" });
window.setTimeout(() => {
driverObj.highlight({ element: ".buttons button:first-child" });
}, 2000);
window.setTimeout(() => {
driverObj.highlight({ element: ".buttons button:nth-child(5)" });
}, 4000);
window.setTimeout(() => {
driverObj.highlight({ element: "h2" });
}, 6000);
});
document.getElementById("scrollable-area-btn").addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "#scrollable-area" });
});
document.getElementById("without-element-btn").addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({
popover: {
title: "driver.js",
description: "Highlight anything, anywhere on the page",
}
});
});
document.getElementById("inner-scroll-area-btn").addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "#third-scroll-paragraph" });
});
document.getElementById("disallow-close").addEventListener("click", () => {
const driverObj = driver({
animate: true,
allowClose: false,
});
document
.getElementById("dark-highlight-btn")
.addEventListener("click", () => {
driver({
animate: true,
opacity: 0.9,
}).highlight({ element: "ul" });
});
document
.getElementById("dim-highlight-btn")
.addEventListener("click", () => {
driver({
animate: true,
opacity: 0.2,
}).highlight({ element: ".buttons" });
});
document
.getElementById("transition-highlight-btn")
.addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "h1" });
window.setTimeout(() => {
driverObj.highlight({ element: ".buttons button:first-child" });
}, 2000);
window.setTimeout(() => {
driverObj.highlight({ element: ".buttons button:nth-child(5)" });
}, 4000);
window.setTimeout(() => {
driverObj.highlight({ element: "h2" });
}, 6000);
});
document
.getElementById("scrollable-area-btn")
.addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "#scrollable-area" });
});
document
.getElementById("inner-scroll-area-btn")
.addEventListener("click", () => {
const driverObj = driver({ animate: true });
driverObj.highlight({ element: "#third-scroll-paragraph" });
});
document
.getElementById("disallow-close")
.addEventListener("click", () => {
const driverObj = driver({
animate: true,
allowClose: false,
});
driverObj.highlight({
element: ".buttons",
});
driverObj.highlight({
element: ".buttons",
});
});
document.getElementById("destroy-btn").addEventListener("click", () => {
driver().destroy();
+6 -6
View File
@@ -19,15 +19,15 @@
},
"devDependencies": {
"@types/jsdom": "^21.1.1",
"@types/node": "^20.1.0",
"@vitest/coverage-c8": "^0.31.0",
"@types/node": "^20.3.0",
"@vitest/coverage-c8": "^0.32.0",
"dts-bundle-generator": "^8.0.1",
"postcss": "^8.4.23",
"postcss": "^8.4.24",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.8",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"vite": "^4.3.5",
"vitest": "^0.31.0"
"typescript": "^5.1.3",
"vite": "^4.3.9",
"vitest": "^0.32.0"
}
}
+409 -3509
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -3,6 +3,8 @@ export type Config = {
smoothScroll?: boolean;
allowClose?: boolean;
opacity?: number;
stagePadding?: number;
stageRadius?: number;
};
let currentConfig: Config = {};
@@ -13,6 +15,8 @@ export function configure(config: Config = {}) {
allowClose: true,
opacity: 0.7,
smoothScroll: false,
stagePadding: 10,
stageRadius: 5,
...config,
};
}
+25 -3
View File
@@ -8,13 +8,34 @@ let previousHighlight: Element | undefined;
let activeHighlight: Element | undefined;
let currentTransitionCallback: undefined | (() => void);
function mountDummyElement(): Element {
const existingDummy = document.getElementById("driver-dummy-element");
if (existingDummy) {
return existingDummy;
}
let element = document.createElement("div");
element.id = "driver-dummy-element";
element.style.width = "0";
element.style.height = "0";
element.style.pointerEvents = "none";
element.style.opacity = "0";
element.style.position = "fixed";
element.style.top = "50%";
element.style.left = "50%";
document.body.appendChild(element);
return element;
}
export function highlight(step: DriveStep) {
const { element } = step;
const elemObj =
typeof element === "string" ? document.querySelector(element) : element;
let elemObj = typeof element === "string" ? document.querySelector(element) : element;
if (!elemObj) {
return;
elemObj = mountDummyElement();
}
previousHighlight = activeHighlight;
@@ -86,6 +107,7 @@ export function destroyHighlight() {
currentTransitionCallback = undefined;
previousHighlight = undefined;
activeHighlight = undefined;
document.getElementById("driver-dummy-element")?.remove();
document.querySelectorAll(".driver-active-element").forEach(element => {
element.classList.remove("driver-active-element");
+6 -5
View File
@@ -1,5 +1,5 @@
import { bringInView } from "./utils";
import { STAGE_PADDING } from "./stage";
import { getConfig } from "./config";
export type Side = "top" | "right" | "bottom" | "left";
export type Alignment = "start" | "center" | "end";
@@ -62,7 +62,7 @@ type PopoverDimensions = {
height: number;
realWidth: number;
realHeight: number;
}
};
function getPopoverDimensions(): PopoverDimensions | undefined {
if (!popover?.wrapper) {
@@ -70,10 +70,11 @@ function getPopoverDimensions(): PopoverDimensions | undefined {
}
const boundingClientRect = popover.wrapper.getBoundingClientRect();
const stagePadding = getConfig("stagePadding") || 0;
return {
width: boundingClientRect.width + STAGE_PADDING + POPOVER_OFFSET,
height: boundingClientRect.height + STAGE_PADDING + POPOVER_OFFSET,
width: boundingClientRect.width + stagePadding + POPOVER_OFFSET,
height: boundingClientRect.height + stagePadding + POPOVER_OFFSET,
realWidth: boundingClientRect.width,
realHeight: boundingClientRect.height,
@@ -178,7 +179,7 @@ export function repositionPopover(element: Element) {
// Configure the popover positioning
const requiredAlignment: Alignment = "start";
const requiredSide: Side = "left" as Side;
const popoverPadding = STAGE_PADDING;
const popoverPadding = getConfig('stagePadding') || 0;
const popoverDimensions = getPopoverDimensions()!;
const popoverArrowDimensions = popover.arrow.getBoundingClientRect();
+8 -11
View File
@@ -3,9 +3,6 @@ import { onDriverClick } from "./events";
import { emit } from "./emitter";
import { getConfig } from "./config";
export const STAGE_PADDING = 10;
export const STAGE_RADIUS = 5;
export type StageDefinition = {
x: number;
y: number;
@@ -24,11 +21,8 @@ export function transitionStage(elapsed: number, duration: number, from: Element
const toDefinition = to.getBoundingClientRect();
const x = easeInOutQuad(elapsed, fromDefinition.x, toDefinition.x - fromDefinition.x, duration);
const y = easeInOutQuad(elapsed, fromDefinition.y, toDefinition.y - fromDefinition.y, duration);
const width = easeInOutQuad(elapsed, fromDefinition.width, toDefinition.width - fromDefinition.width, duration);
const height = easeInOutQuad(elapsed, fromDefinition.height, toDefinition.height - fromDefinition.height, duration);
activeStagePosition = {
@@ -146,17 +140,20 @@ function generateSvgCutoutPathString(stage: StageDefinition) {
const windowX = window.innerWidth;
const windowY = window.innerHeight;
const stageWidth = stage.width + STAGE_PADDING * 2;
const stageHeight = stage.height + STAGE_PADDING * 2;
const stagePadding = getConfig('stagePadding') || 0;
const stageRadius = getConfig('stageRadius') || 0;
const stageWidth = stage.width + stagePadding * 2;
const stageHeight = stage.height + stagePadding * 2;
// prevent glitches when stage is too small for radius
const limitedRadius = Math.min(STAGE_RADIUS, stageWidth / 2, stageHeight / 2);
const limitedRadius = Math.min(stageRadius, stageWidth / 2, stageHeight / 2);
// no value below 0 allowed + round down
const normalizedRadius = Math.floor(Math.max(limitedRadius, 0));
const highlightBoxX = stage.x - STAGE_PADDING + normalizedRadius;
const highlightBoxY = stage.y - STAGE_PADDING;
const highlightBoxX = stage.x - stagePadding + normalizedRadius;
const highlightBoxY = stage.y - stagePadding;
const highlightBoxWidth = stageWidth - normalizedRadius * 2;
const highlightBoxHeight = stageHeight - normalizedRadius * 2;