mirror of
https://github.com/kamranahmedse/driver.js.git
synced 2026-10-31 03:52:13 +08:00
Hide the popover while waiting for an element
This commit is contained in:
@@ -89,7 +89,7 @@ driverObj.drive();
|
||||
|
||||
## Waiting for Elements
|
||||
|
||||
When you know the next element is rendered on demand, you often don't need the manual `onNextClick` dance at all. Give the step a `waitForElement` timeout and the tour waits for the element to appear, staying on the current step in the meantime. Pair it with `advanceOnClick` when the highlighted element itself is what triggers the rendering, e.g. a button that opens a modal:
|
||||
When you know the next element is rendered on demand, you often don't need the manual `onNextClick` dance at all. Give the step a `waitForElement` timeout and the tour waits for the element to appear, staying on the current step with its popover hidden in the meantime. Pair it with `advanceOnClick` when the highlighted element itself is what triggers the rendering, e.g. a button that opens a modal:
|
||||
|
||||
```js
|
||||
const driverObj = driver({
|
||||
|
||||
@@ -25,6 +25,9 @@ ships, these entries move under a versioned heading.
|
||||
their button is hidden or disabled, and Escape does nothing when the close
|
||||
button is disabled.
|
||||
([#589](https://github.com/nilbuild/driver.js/issues/589))
|
||||
- The current popover is hidden while `waitForElement` waits for the next
|
||||
step's element, so a stale step no longer stays on screen.
|
||||
([#578](https://github.com/nilbuild/driver.js/issues/578))
|
||||
- Only one instance is on screen at a time. Starting a tour or highlight closes
|
||||
any other active instance; it gets `onDeselected` and `onDestroyed` but not
|
||||
`onDestroyStarted`.
|
||||
|
||||
@@ -84,8 +84,8 @@ type Config = {
|
||||
|
||||
// Wait up to this many milliseconds for a step's element to appear before
|
||||
// treating it as missing (centered fallback popover, or a skip when
|
||||
// skipMissingElement is set). The current step stays highlighted while
|
||||
// waiting. Useful when the next element is rendered on demand, e.g. inside
|
||||
// skipMissingElement is set). The current step stays highlighted, with its
|
||||
// popover hidden, while waiting. Useful when the next element is rendered on demand, e.g. inside
|
||||
// a modal that the previous step's click opens. Can be configured at the
|
||||
// step level. (default: 0, off)
|
||||
waitForElement?: number;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { CodeSample } from "../../components/CodeSample.tsx";
|
||||
Sometimes the best way forward in a tour is the product itself: click the button you are pointing at, not a "Next" in the popover. Two options make this work without any custom hooks:
|
||||
|
||||
- `advanceOnClick` advances the tour when the highlighted element is clicked, exactly as if the next button was pressed. The element's own click behavior still runs.
|
||||
- `waitForElement` makes a step wait up to the given number of milliseconds for its element to appear, staying on the current step in the meantime.
|
||||
- `waitForElement` makes a step wait up to the given number of milliseconds for its element to appear, staying on the current step with its popover hidden in the meantime.
|
||||
|
||||
Both can be set for the whole tour or per step. The tour below has `advanceOnClick` enabled, so you can click the highlighted lines to walk through it.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AllowedButtons, destroyPopover, Popover } from "./popover";
|
||||
import { AllowedButtons, destroyPopover, hidePopover, Popover } from "./popover";
|
||||
import { destroyOverlay } from "./overlay";
|
||||
import { destroyEvents, initEvents, requireRefresh } from "./events";
|
||||
import { Config, createContext, DriverHook } from "./context";
|
||||
@@ -319,10 +319,11 @@ export function driver(options: Config = {}): Driver {
|
||||
|
||||
const currentStep = steps[stepIndex];
|
||||
|
||||
// The current step stays highlighted while waiting; a timeout falls
|
||||
// through to the usual missing-element handling below.
|
||||
// The current step stays highlighted, with its popover hidden, while
|
||||
// waiting; a timeout falls through to the usual missing-element handling below.
|
||||
const waitTimeout = currentStep.waitForElement ?? ctx.getConfig("waitForElement") ?? 0;
|
||||
if (!hasWaitedForElement && waitTimeout > 0 && currentStep.element && !resolveElement(currentStep.element)) {
|
||||
hidePopover(ctx.getState("popover"));
|
||||
waitForStepElement(currentStep, waitTimeout, () => drive(stepIndex, true));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createDriver, nextFrame, popoverTitle, useDriverHarness } from "./utils";
|
||||
import { createDriver, nextFrame, popoverEl, popoverTitle, useDriverHarness } from "./utils";
|
||||
|
||||
useDriverHarness();
|
||||
|
||||
@@ -36,6 +36,45 @@ describe("waitForElement", () => {
|
||||
expect(d.getActiveElement()?.id).toBe("late");
|
||||
});
|
||||
|
||||
it("hides the current popover while waiting", async () => {
|
||||
const d = createDriver({
|
||||
animate: false,
|
||||
steps: [
|
||||
{ element: "#intro", popover: { title: "Step 1" } },
|
||||
{ element: "#late", waitForElement: 500, popover: { title: "Step 2" } },
|
||||
],
|
||||
});
|
||||
d.drive();
|
||||
d.moveNext();
|
||||
|
||||
expect(popoverEl()?.style.display).toBe("none");
|
||||
expect(document.getElementById("intro")?.classList.contains("driver-active-element")).toBe(true);
|
||||
|
||||
appendElement("late");
|
||||
await tick();
|
||||
|
||||
expect(popoverEl()?.style.display).toBe("block");
|
||||
expect(popoverTitle()).toBe("Step 2");
|
||||
});
|
||||
|
||||
it("shows the fallback popover when the wait times out", async () => {
|
||||
const d = createDriver({
|
||||
animate: false,
|
||||
steps: [
|
||||
{ element: "#intro", popover: { title: "Step 1" } },
|
||||
{ element: "#never", waitForElement: 40, popover: { title: "Step 2" } },
|
||||
],
|
||||
});
|
||||
d.drive();
|
||||
d.moveNext();
|
||||
expect(popoverEl()?.style.display).toBe("none");
|
||||
|
||||
await tick(80);
|
||||
|
||||
expect(popoverEl()?.style.display).toBe("block");
|
||||
expect(popoverTitle()).toBe("Step 2");
|
||||
});
|
||||
|
||||
it("waits for the first step's element on the initial drive", async () => {
|
||||
const d = createDriver({
|
||||
animate: false,
|
||||
|
||||
Reference in New Issue
Block a user