From b4c27c5abf261ee7ea216ffc8283b028865791cc Mon Sep 17 00:00:00 2001 From: binrysearch Date: Tue, 3 Sep 2024 22:13:22 +0100 Subject: [PATCH] add root --- src/packages/hint/tooltip.ts | 2 +- src/packages/tour/addOverlayLayer.ts | 34 ++--- src/packages/tour/exitIntro.ts | 10 +- src/packages/tour/position.ts | 2 +- src/packages/tour/showElement.ts | 63 ++++++--- src/packages/tour/tour.ts | 16 +++ src/packages/tour/tourTooltip.ts | 121 ++++++++++-------- src/util/appendChild.ts | 2 +- src/util/createElement.ts | 2 +- ...eTo.test.ts => positionRelativeTo.test.ts} | 2 +- ...ionRelativeTo.ts => positionRelativeTo.ts} | 36 ++++-- src/util/removeChild.ts | 2 +- src/util/setStyle.ts | 23 ---- src/util/{setStyle.test.ts => style.test.ts} | 2 +- src/util/style.ts | 31 +++++ 15 files changed, 217 insertions(+), 131 deletions(-) rename src/util/{setPositionRelativeTo.test.ts => positionRelativeTo.test.ts} (97%) rename src/util/{setPositionRelativeTo.ts => positionRelativeTo.ts} (74%) delete mode 100644 src/util/setStyle.ts rename src/util/{setStyle.test.ts => style.test.ts} (97%) create mode 100644 src/util/style.ts diff --git a/src/packages/hint/tooltip.ts b/src/packages/hint/tooltip.ts index 2093428be..b34050cab 100644 --- a/src/packages/hint/tooltip.ts +++ b/src/packages/hint/tooltip.ts @@ -9,7 +9,7 @@ import { Hint } from "./hint"; import createElement from "../../util/createElement"; import { setClass } from "../../util/className"; import { hideHint } from "./hide"; -import { setPositionRelativeTo } from "../../util/setPositionRelativeTo"; +import { setPositionRelativeTo } from "../../util/positionRelativeTo"; import DOMEvent from "../../util/DOMEvent"; import getOffset from "../../util/getOffset"; import { HintTooltip } from "./hintTooltip"; diff --git a/src/packages/tour/addOverlayLayer.ts b/src/packages/tour/addOverlayLayer.ts index bebac97a7..c2e9d3303 100644 --- a/src/packages/tour/addOverlayLayer.ts +++ b/src/packages/tour/addOverlayLayer.ts @@ -1,7 +1,9 @@ -import createElement from "../../util/createElement"; -import setStyle from "../../util/setStyle"; +import { style } from "../../util/style"; import { Tour } from "./tour"; import { overlayClassName } from "./classNames"; +import van from "../dom/van"; + +const { div } = van.tags; /** * Add overlay layer to the page @@ -9,25 +11,23 @@ import { overlayClassName } from "./classNames"; * @api private */ export default function addOverlayLayer(tour: Tour) { - const overlayLayer = createElement("div", { - className: overlayClassName, - }); + const exitOnOverlayClick = tour.getOption("exitOnOverlayClick") === true; - setStyle(overlayLayer, { - top: 0, - bottom: 0, - left: 0, - right: 0, - position: "fixed", + const overlayLayer = div({ + className: overlayClassName, + style: style({ + top: 0, + bottom: 0, + left: 0, + right: 0, + position: "fixed", + cursor: exitOnOverlayClick ? "pointer" : "auto", + }), }); - tour.getTargetElement().appendChild(overlayLayer); - - if (tour.getOption("exitOnOverlayClick") === true) { - setStyle(overlayLayer, { - cursor: "pointer", - }); + tour.appendToRoot(overlayLayer); + if (exitOnOverlayClick) { overlayLayer.onclick = async () => { await tour.exit(); }; diff --git a/src/packages/tour/exitIntro.ts b/src/packages/tour/exitIntro.ts index e4a1aa070..d9f6eb1e2 100644 --- a/src/packages/tour/exitIntro.ts +++ b/src/packages/tour/exitIntro.ts @@ -46,11 +46,11 @@ export default async function exitIntro( } } - const referenceLayer = queryElementByClassName( - tooltipReferenceLayerClassName, - targetElement - ); - removeChild(referenceLayer); + //const referenceLayer = queryElementByClassName( + // tooltipReferenceLayerClassName, + // targetElement + //); + //removeChild(referenceLayer); //remove disableInteractionLayer const disableInteractionLayer = queryElementByClassName( diff --git a/src/packages/tour/position.ts b/src/packages/tour/position.ts index 2c1aba139..45f22c231 100644 --- a/src/packages/tour/position.ts +++ b/src/packages/tour/position.ts @@ -1,4 +1,4 @@ -import { setPositionRelativeTo } from "../../util/setPositionRelativeTo"; +import { setPositionRelativeTo } from "../../util/positionRelativeTo"; import { TourStep } from "./steps"; /** diff --git a/src/packages/tour/showElement.ts b/src/packages/tour/showElement.ts index d5feabade..5b4dadd9f 100644 --- a/src/packages/tour/showElement.ts +++ b/src/packages/tour/showElement.ts @@ -4,7 +4,7 @@ import { addClass, setClass } from "../../util/className"; import { TourStep, nextStep, previousStep } from "./steps"; import removeShowElement from "./removeShowElement"; import createElement from "../../util/createElement"; -import setStyle from "../../util/setStyle"; +import setStyle, { style } from "../../util/style"; import appendChild from "../../util/appendChild"; import { disableInteractionClassName, @@ -21,6 +21,35 @@ import { import { setPositionRelativeToStep } from "./position"; import getPropValue from "../../util/getPropValue"; import { TourTooltip } from "./tourTooltip"; +import van from "../dom/van"; + +const { div } = van.tags; + +/** + * Add disableinteraction layer and adjust the size and position of the layer + * + * @api private + */ +export const _disableInteraction = (tour: Tour, step: TourStep) => { + let disableInteractionLayer = queryElementByClassName( + disableInteractionClassName + ); + + if (disableInteractionLayer === null) { + disableInteractionLayer = createElement("div", { + className: disableInteractionClassName, + }); + + tour.getTargetElement().appendChild(disableInteractionLayer); + } + + setPositionRelativeToStep( + tour.getTargetElement(), + disableInteractionLayer, + step, + tour.getOption("helperElementPadding") + ); + }; /** * To set the show element @@ -76,7 +105,6 @@ export default async function _showElement(tour: Tour, step: TourStep) { oldReferenceLayer ); - //update or reset the helper highlight class setClass(oldHelperLayer, highlightClass); @@ -122,21 +150,20 @@ export default async function _showElement(tour: Tour, step: TourStep) { // end of old element if-else condition } else { - const helperLayer = createElement("div", { + const helperLayer = div({ className: highlightClass, + style: style({ + // the inner box shadow is the border for the highlighted element + // the outer box shadow is the overlay effect + "box-shadow": `0 0 1px 2px rgba(33, 33, 33, 0.8), rgba(33, 33, 33, ${tour + .getOption("overlayOpacity") + .toString()}) 0 0 0 5000px`, + }), }); - const referenceLayer = createElement("div", { + const referenceLayer = div({ className: tooltipReferenceLayerClassName, }); - setStyle(helperLayer, { - // the inner box shadow is the border for the highlighted element - // the outer box shadow is the overlay effect - "box-shadow": `0 0 1px 2px rgba(33, 33, 33, 0.8), rgba(33, 33, 33, ${tour - .getOption("overlayOpacity") - .toString()}) 0 0 0 5000px`, - }); - // target is within a scrollable element scrollParentToElement( tour.getOption("scrollToElement"), @@ -159,8 +186,8 @@ export default async function _showElement(tour: Tour, step: TourStep) { ); //add helper layer to target element - appendChild(tour.getTargetElement(), helperLayer, true); - appendChild(tour.getTargetElement(), referenceLayer); + tour.appendToRoot(helperLayer, true); + tour.appendToRoot(referenceLayer); const tooltip = TourTooltip({ positionPrecedence: tour.getOption("positionPrecedence"), @@ -230,7 +257,8 @@ export default async function _showElement(tour: Tour, step: TourStep) { dontShowAgainLabel: tour.getOption("dontShowAgainLabel"), }); - referenceLayer.appendChild(tooltip); + van.add(referenceLayer, tooltip); + //referenceLayer.appendChild(tooltip); // change the scroll of the window, if needed scrollTo( @@ -255,5 +283,10 @@ export default async function _showElement(tour: Tour, step: TourStep) { setShowElement(step.element as HTMLElement); + //disable interaction + if (step.disableInteraction) { + _disableInteraction(tour, step); + } + await tour.callback("afterChange")?.call(tour, step.element); } diff --git a/src/packages/tour/tour.ts b/src/packages/tour/tour.ts index b61e9d4da..4b25a0527 100644 --- a/src/packages/tour/tour.ts +++ b/src/packages/tour/tour.ts @@ -22,6 +22,7 @@ import DOMEvent from "../../util/DOMEvent"; import onKeyDown from "./onKeyDown"; import onResize from "./onResize"; import van from "../dom/van"; +import appendChild from "src/util/appendChild"; /** * Intro.js Tour class @@ -33,6 +34,7 @@ export class Tour implements Package { private _direction: "forward" | "backward"; private readonly _targetElement: HTMLElement; private _options: TourOptions; + private _root: HTMLElement; private readonly callbacks: { beforeChange?: introBeforeChangeCallback; @@ -375,10 +377,24 @@ export class Tour implements Package { } } + public appendToRoot(element: HTMLElement, animate = false) { + appendChild(this._root, element, animate); + } + + private createRoot() { + if (!this._root) { + const { div } = van.tags; + this._root = div({ className: "introjs" }); + this.getTargetElement().appendChild(this._root); + } + } + /** * Starts the tour and shows the first step */ async start() { + this.createRoot(); + if (await start(this)) { this.enableKeyboardNavigation(); this.enableRefreshOnResize(); diff --git a/src/packages/tour/tourTooltip.ts b/src/packages/tour/tourTooltip.ts index 7eb42efb7..a9a0efac0 100644 --- a/src/packages/tour/tourTooltip.ts +++ b/src/packages/tour/tourTooltip.ts @@ -425,66 +425,77 @@ export const TourTooltip = ({ dontShowAgainLabel, ...props }: TourTooltipProps) => { - const children = []; + const step = van.derive(() => + currentStep.val !== undefined ? steps[currentStep.val] : null + ); - const step = van.derive(() => steps[currentStep.val!]); - const title = van.derive(() => step.val!.title); - const text = van.derive(() => step.val!.intro); - const position = van.derive(() => step.val!.position); - const targetOffset = van.derive(() => getOffset(step.val!.element as HTMLElement)); + return () => { + // there is nothing to be shown if the step is not defined + if (!step.val) { + return null; + } + + const children = []; + const title = van.derive(() => step.val!.title); + const text = van.derive(() => step.val!.intro); + const position = van.derive(() => step.val!.position); + const targetOffset = van.derive(() => + getOffset(step.val!.element as HTMLElement) + ); - children.push(Header({ title: title.val!, skipLabel, onSkipClick })); + children.push(Header({ title: title.val!, skipLabel, onSkipClick })); - children.push( - div({ className: tooltipTextClassName }, p(text)), -); + children.push(div({ className: tooltipTextClassName }, p(text))); - if (dontShowAgain) { - children.push(DontShowAgain({ dontShowAgainLabel, onDontShowAgainChange })); - } + if (dontShowAgain) { + children.push( + DontShowAgain({ dontShowAgainLabel, onDontShowAgainChange }) + ); + } - if (bullets) { - children.push(Bullets({ steps, currentStep, onBulletClick })); - } + if (bullets) { + children.push(Bullets({ steps, currentStep, onBulletClick })); + } - if (progress) { - children.push( - ProgressBar({ steps, currentStep, progressBarAdditionalClass }) - ); - } - - if (stepNumbers) { - children.push(StepNumber({ step: step.val!, steps, stepNumbersOfLabel })); - } - - if (buttons) { - children.push( - Buttons({ - steps, - currentStep, - - nextLabel: nextLabel, - onNextClick: onNextClick, - - prevLabel: prevLabel, - onPrevClick: onPrevClick, - - buttonClass, - nextToDone, - doneLabel, - hideNext, - hidePrev, - }) + if (progress) { + children.push( + ProgressBar({ steps, currentStep, progressBarAdditionalClass }) + ); + } + + if (stepNumbers) { + children.push(StepNumber({ step: step.val!, steps, stepNumbersOfLabel })); + } + + if (buttons) { + children.push( + Buttons({ + steps, + currentStep, + + nextLabel: nextLabel, + onNextClick: onNextClick, + + prevLabel: prevLabel, + onPrevClick: onPrevClick, + + buttonClass, + nextToDone, + doneLabel, + hideNext, + hidePrev, + }) + ); + } + + return Tooltip( + { + ...props, + hintMode: false, + position, + targetOffset, + }, + children ); - } - - return Tooltip( - { - ...props, - hintMode: false, - position, - targetOffset - }, - children - ); + }; }; diff --git a/src/util/appendChild.ts b/src/util/appendChild.ts index b09d7b3ca..93c72e8a1 100644 --- a/src/util/appendChild.ts +++ b/src/util/appendChild.ts @@ -1,4 +1,4 @@ -import setStyle from "./setStyle"; +import setStyle from "./style"; /** * Appends `element` to `parentElement` diff --git a/src/util/createElement.ts b/src/util/createElement.ts index b3d3e6bee..f27f662f0 100644 --- a/src/util/createElement.ts +++ b/src/util/createElement.ts @@ -1,4 +1,4 @@ -import setStyle from "./setStyle"; +import setStyle from "./style"; /** * Create a DOM element with various attributes diff --git a/src/util/setPositionRelativeTo.test.ts b/src/util/positionRelativeTo.test.ts similarity index 97% rename from src/util/setPositionRelativeTo.test.ts rename to src/util/positionRelativeTo.test.ts index 2392f6fab..101e0c02a 100644 --- a/src/util/setPositionRelativeTo.test.ts +++ b/src/util/positionRelativeTo.test.ts @@ -1,4 +1,4 @@ -import { setPositionRelativeTo } from "./setPositionRelativeTo"; +import { setPositionRelativeTo } from "./positionRelativeTo"; import createElement from "./createElement"; import { getBoundingClientRectSpy } from "../../tests/jest/helper"; diff --git a/src/util/setPositionRelativeTo.ts b/src/util/positionRelativeTo.ts similarity index 74% rename from src/util/setPositionRelativeTo.ts rename to src/util/positionRelativeTo.ts index 2db5bda06..bea93a94b 100644 --- a/src/util/setPositionRelativeTo.ts +++ b/src/util/positionRelativeTo.ts @@ -1,13 +1,9 @@ import getOffset from "./getOffset"; import isFixed from "./isFixed"; import { removeClass, addClass } from "./className"; -import setStyle from "./setStyle"; +import setStyle from "./style"; -/** - * Sets the position of the element relative to the target element - * @api private - */ -export const setPositionRelativeTo = ( +export const getPositionRelativeTo = ( relativeElement: HTMLElement, element: HTMLElement, targetElement: HTMLElement, @@ -28,11 +24,33 @@ export const setPositionRelativeTo = ( const position = getOffset(targetElement, relativeElement); - //set new position to helper layer - setStyle(element, { + return { width: `${position.width + padding}px`, height: `${position.height + padding}px`, top: `${position.top - padding / 2}px`, left: `${position.left - padding / 2}px`, - }); + }; +}; + +/** + * Sets the position of the element relative to the target element + * @api private + */ +export const setPositionRelativeTo = ( + relativeElement: HTMLElement, + element: HTMLElement, + targetElement: HTMLElement, + padding: number +) => { + const styles = getPositionRelativeTo( + relativeElement, + element, + targetElement, + padding + ); + + if (!styles) return; + + //set new position to helper layer + setStyle(element, styles); }; diff --git a/src/util/removeChild.ts b/src/util/removeChild.ts index d9355551f..9a2b6232e 100644 --- a/src/util/removeChild.ts +++ b/src/util/removeChild.ts @@ -1,4 +1,4 @@ -import setStyle from "./setStyle"; +import setStyle from "./style"; /** * Removes `element` from `parentElement` diff --git a/src/util/setStyle.ts b/src/util/setStyle.ts deleted file mode 100644 index 985d3a537..000000000 --- a/src/util/setStyle.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Sets the style of an DOM element - */ -export default function setStyle( - element: HTMLElement, - style: string | { [key: string]: string | number } -) { - let cssText = ""; - - if (element.style.cssText) { - cssText += element.style.cssText; - } - - if (typeof style === "string") { - cssText += style; - } else { - for (const rule in style) { - cssText += `${rule}:${style[rule]};`; - } - } - - element.style.cssText = cssText; -} diff --git a/src/util/setStyle.test.ts b/src/util/style.test.ts similarity index 97% rename from src/util/setStyle.test.ts rename to src/util/style.test.ts index f143360d0..479291c59 100644 --- a/src/util/setStyle.test.ts +++ b/src/util/style.test.ts @@ -1,4 +1,4 @@ -import setStyle from "./setStyle"; +import setStyle from "./style"; describe("setStyle", () => { test("should set style when the list is empty", () => { diff --git a/src/util/style.ts b/src/util/style.ts new file mode 100644 index 000000000..68e4b1839 --- /dev/null +++ b/src/util/style.ts @@ -0,0 +1,31 @@ +export const style = (style: { [key: string]: string | number }) => { + let cssText = ""; + + for (const rule in style) { + cssText += `${rule}:${style[rule]};`; + } + + return cssText; +}; + +/** + * Sets the style of an DOM element + */ +export default function setStyle( + element: HTMLElement, + styles: string | { [key: string]: string | number } +) { + let cssText = ""; + + if (element.style.cssText) { + cssText += element.style.cssText; + } + + if (typeof styles === "string") { + cssText += styles; + } else { + cssText += style(styles); + } + + element.style.cssText = cssText; +}