From 0d9dc42295dc0b3e398fa6b10184bb8565e225b3 Mon Sep 17 00:00:00 2001 From: iRittikSharma38 Date: Fri, 2 May 2025 12:48:29 +0530 Subject: [PATCH 1/2] FIX : prevent tour from closing on left arrow key at first step --- src/driver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver.ts b/src/driver.ts index 9108aff9..eb6139f0 100644 --- a/src/driver.ts +++ b/src/driver.ts @@ -81,6 +81,7 @@ export function driver(options: Config = {}): Driver { function movePrevious() { const activeIndex = getState("activeIndex"); + if (activeIndex === 0) return; const steps = getConfig("steps") || []; if (typeof activeIndex === "undefined") { return; @@ -182,10 +183,9 @@ export function driver(options: Config = {}): Driver { destroy(); return; } - + if (stepIndex < 0) return; if (!steps[stepIndex]) { destroy(); - return; } From 31d907b21fb81f934712fbc4f8d002a1387bc7cf Mon Sep 17 00:00:00 2001 From: iRittikSharma38 Date: Sat, 3 May 2025 21:26:08 +0530 Subject: [PATCH 2/2] feat: add error handling for invalid usage of driver API methods --- src/driver.ts | 20 ++++++++++++++++++-- src/errors.ts | 12 ++++++++++++ src/utils.ts | 7 +++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/errors.ts diff --git a/src/driver.ts b/src/driver.ts index eb6139f0..bb05fd44 100644 --- a/src/driver.ts +++ b/src/driver.ts @@ -6,6 +6,8 @@ import { destroyHighlight, highlight } from "./highlight"; import { destroyEmitter, listen } from "./emitter"; import { getState, resetState, setState } from "./state"; import "./driver.css"; +import { InvalidDriverActionError } from "./errors"; +import { DRIVER_MARKER, isDriver } from "./utils"; export type DriveStep = { element?: string | Element | (() => Element); @@ -38,6 +40,7 @@ export interface Driver { hasPreviousStep: () => boolean; highlight: (step: DriveStep) => void; destroy: () => void; + [DRIVER_MARKER]: true; } export function driver(options: Config = {}): Driver { @@ -72,6 +75,10 @@ export function driver(options: Config = {}): Driver { } const nextStepIndex = activeIndex + 1; + // @ts-ignore + if (isDriver(this) && nextStepIndex >= steps.length) { + throw new InvalidDriverActionError("Cannot move to next step. Already at the last step."); + } if (steps[nextStepIndex]) { drive(nextStepIndex); } else { @@ -81,13 +88,15 @@ export function driver(options: Config = {}): Driver { function movePrevious() { const activeIndex = getState("activeIndex"); - if (activeIndex === 0) return; const steps = getConfig("steps") || []; if (typeof activeIndex === "undefined") { return; } const previousStepIndex = activeIndex - 1; + if (previousStepIndex < 0) { + throw new InvalidDriverActionError("Cannot move to previous step. Already at the first step."); + } if (steps[previousStepIndex]) { drive(previousStepIndex); } else { @@ -98,6 +107,10 @@ export function driver(options: Config = {}): Driver { function moveTo(index: number) { const steps = getConfig("steps") || []; + if (index < 0 || index >= steps.length) { + throw new RangeError(); + } + if (steps[index]) { drive(index); } else { @@ -183,7 +196,9 @@ export function driver(options: Config = {}): Driver { destroy(); return; } - if (stepIndex < 0) return; + if (stepIndex < 0 || stepIndex >= steps.length) { + throw new RangeError(); + } if (!steps[stepIndex]) { destroy(); return; @@ -370,6 +385,7 @@ export function driver(options: Config = {}): Driver { destroy: () => { destroy(false); }, + [DRIVER_MARKER]: true, }; setCurrentDriver(api); diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 00000000..3d25a810 --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,12 @@ +export class InvalidDriverActionError extends Error { + constructor(errorMessage: string) { + super(errorMessage); + this.name = "InvalidDriverActionError"; + + Object.setPrototypeOf(this, InvalidDriverActionError.prototype); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, InvalidDriverActionError); + } + } +} diff --git a/src/utils.ts b/src/utils.ts index 1ff37daf..25cf6f92 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,5 @@ import { getConfig } from "./config"; +import { Driver } from "./driver"; export function easeInOutQuad(elapsed: number, initialValue: number, amountOfChange: number, duration: number): number { if ((elapsed /= duration / 2) < 1) { @@ -65,3 +66,9 @@ function isElementInView(element: Element) { export function isElementVisible(el: HTMLElement) { return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); } + +export const DRIVER_MARKER = Symbol("Driver"); + +export function isDriver(obj: any): obj is Driver { + return obj && obj[DRIVER_MARKER] === true; +}