Commit Graph
624 Commits
Author SHA1 Message Date
Kamran Ahmed dd468dcc10 Remove the hints demo from the homepage examples
The demo's beacon placement on the hero didn't sit right, and the
homepage grid works fine without it; the hints guide and its live
samples remain the place to try hints. The shorter 'and more ...'
label stays.
2026-07-17 12:22:38 +01:00
Kamran Ahmed fe504ad6f0 Add a hints example to the homepage and simplify the hint-to-tour docs
The homepage examples grid gains a Hints button that toggles three
beacons on the hero: one plain dismissable hint, one whose button starts
a short tour through onButtonClick (showing the two features hand off to
each other), and one whose button leads to the hints guide. The last-row
label shrinks from 'and much more ...' to 'and more ...' so the row
keeps to one line.

The guide's hint-launches-tour example now uses buttonText plus
onButtonClick instead of hand-building a button in onPopoverRender,
which stays mentioned for additional buttons.
2026-07-17 11:59:37 +01:00
Kamran Ahmed b4d221faf7 Add onButtonClick to take over the hint button
The built-in button always dismissed; repurposing it meant hiding it and
rebuilding one in onPopoverRender. onButtonClick (per hint or instance
wide, hint wins) now runs instead of dismissing, mirroring how a tour's
onNextClick takes over the default advance; call dismiss() from the hook
to keep the old behavior. Custom and extra buttons remain the
onPopoverRender pattern, same as tours.
2026-07-17 11:30:10 +01:00
Kamran Ahmed 3e74fee890 Mention hints across the getting-started docs and the landing page
Basic Usage gains a live hints demo with its code, replacing a dangling
paragraph that promised a single-step tour example which never followed.
Installation covers the hints entry for both npm (separate import,
self-contained stylesheet) and the CDN (hints.iife.js, hints.css, and
the window.driverHints global). Theming points at the beacon CSS
variables and the Styling Hints examples. The landing marquee names
tours, highlights and hints, and the meta description mentions hints.
2026-07-17 11:26:36 +01:00
Kamran Ahmed cd50754091 Document hints on the Configuration and API Reference pages
Hints were only covered by their own guide. Configuration gains the
HintsConfig and DriverHint sections in the same annotated-type style as
the tour's, and API Reference gains the hints() factory with every
instance method. Both cross-link the guide, and the API page links the
new configuration anchor. Also replaces a pre-existing em dash in the
onDoneClick note.
2026-07-17 09:55:59 +01:00
Kamran Ahmed 09484c7261 Clean up the hints module
show() now mounts hints whose elements have appeared since the last
call, which the docs already promised but only a full hide()/show()
delivered; mountHints() skips what is already on the page, making
show() naturally idempotent and simpler.

The closePopover()/close() pair collapses into one function, the
scroll and resize listeners use requireRefresh directly instead of
wrapper closures, and config/dismissed become consts.

Comments get a pass: the HintsConfig overlay comment still described
the pre-cutout semantics (beacons above the overlay) and is corrected;
obvious comments are dropped, the load-bearing ones tightened, and em
dashes across source comments replaced per Kamran's preference.
2026-07-16 22:25:21 +01:00
Kamran Ahmed 95df19e079 Give the hint popover and its arrow one seamless shadow
box-shadow follows the popover's rectangular box, so the protruding
arrow cast nothing and read as a flat notch against whatever sat behind
it. The hint popover now uses a drop-shadow filter instead, which
follows the rendered silhouette: the rounded box and the arrow cast a
single continuous shadow, with no border tricks and no assumptions
about the theme's colors. Tours are untouched since their overlay
already gives the arrow contrast.
2026-07-16 21:50:58 +01:00
Kamran Ahmed 8d2e5c9f78 Open the hints guide with the overlay demo
The hero example on the guide turns the optional overlay on, so the
first interaction shows the spotlight, and its code block now matches
what the demo runs. The lead-in names the overlay as optional so the
default stays clear.
2026-07-16 21:16:30 +01:00
Kamran Ahmed 7336c67097 Lead the hints examples with the overlay and drop the em dashes
The Dimming the page sample moves to the top of Styling Hints. The em
dashes across the hints docs copy, the demo component and the changelog
entries are rephrased with plain punctuation.
2026-07-16 21:04:35 +01:00
Kamran Ahmed 24763f9ef2 Anchor overlay-mode hints to the element and enlarge the hint arrow
With the overlay up, an open hint now reads exactly like a tour step:
the popover anchors to the element (clearing the cutout ring and lining
up with its edge) instead of hanging off the beacon, and the beacon
steps aside while its popover is up — the spotlight does the pointing.
Suggested by Kamran: once the dot has been clicked, it is just noise
inside the cutout. Without the overlay nothing changes; the dot remains
the anchor and the toggle. Dim-click, Escape and Got it all still close.

The hint arrow also grows to 14px (7px borders) — the tour's 10px
triangle read small next to a 24px beacon. Tours are untouched. The
arrow placement code now measures the arrow's real box instead of
assuming the constant, so restyled arrows keep their tip on target;
the beacon-shift constant is the one place the size is assumed, since
it runs before the popover exists.
2026-07-16 20:55:19 +01:00
Kamran Ahmed 51b66dcfe9 Cut the active element out of the hint overlay
The overlay is now the same spotlight the tour draws: an svg dim with a
rounded cutout around the open hint's element (the path generator moves
out of the tour's context into a pure function both share). The element
stays visible and interactive inside the cutout — the svg lets pointer
events through and only the dimmed path catches them, so clicking the
dim still closes the hint.

The other beacons now wait under the overlay instead of floating above
it; only the open hint's beacon (via its aria-expanded state) and its
popover rise above. The cutout tracks the element on scroll and resize.

The arrow's drop-shadow halo is gone: it read as a dirty outline against
light pages — tours never needed one because the arrow sits against the
dark overlay, and hints now either touch the colored beacon (no overlay)
or sit against the dim (overlay), so the plain white triangle works in
both.
2026-07-16 20:42:14 +01:00
Kamran Ahmed 2884c76d57 Show hints with default styling in the docs and add a customization page
The guide's live sample dropped the docs theme so readers see the
default look first. New Styling Hints page under Examples: beacon color
and size through CSS variables and per-beacon classes, static beacons,
custom and hidden dismiss buttons, the overlay focus mode, and popover
theming. HintsSample takes an id prefix and instance config so several
samples share a page.
2026-07-16 20:23:44 +01:00
Kamran Ahmed beb2935f25 Point the hint arrow at the beacon, resize the dot, add an optional overlay
Three fixes to how hints look and behave:

The popover arrow used to land beside the dot: it sits a fixed corner
inset from the popover's edge, while start/end alignment put the popover
edge flush with the beacon. The position options now pass the difference
between the arrow tip and the beacon's half-size as the alignment
pull-back, so the arrow points at the beacon's center. The arrow also
gets a faint halo — it is a white triangle designed to sit against a
tour's darkened overlay, and vanished on light pages without one.

The default beacon grows from 20px to 24px (still --driver-hint-size),
and defaults to a lighter indigo.

New opt-in overlay: overlay: true dims the page while a hint is open
(overlayColor/overlayOpacity to taste). Beacons and the popover sit
above it so hints stay clickable, and clicking the dimmed page closes
the hint like any outside click. Verified in a real browser — beacons
float above the dim, arrow centered on the dot.
2026-07-16 20:23:44 +01:00
Kamran Ahmed 572811582d Document hints and add the changelog entry
A Hints guide in the docs Introduction section with a live sample
component (self-contained mock UI the beacons attach to), covering the
close-vs-dismiss semantics, the localStorage persistence recipe, beacon
placement/styling and the full options and methods reference. The docs
app gains driver.js/hints and hints.css source aliases for HMR, same as
the playground.

The Unreleased changelog section lists the hints entry, the new CSS
variables, the sideEffects field, the shared popover layer and the
tsdown build migration — which also makes the release flow green: the
release aborts on an empty Unreleased section.
2026-07-16 19:58:55 +01:00
Kamran Ahmed 75edd1b4bc Restructure as a Turborepo monorepo
packages/driver is the library (still published as driver.js, with
repository.directory set); playground and docs move to apps/. One root
pnpm workspace and lockfile replace the three standalone projects, with
turbo orchestrating build/test/lint:package (apps depend on the library
build; local + CI caching via .turbo).

Apps keep importing the library from source for HMR — the aliases now
point at ../../packages/driver/src and each app gains a workspace:*
dependency so the task graph knows the edge. The dev-server fs scope
widens to the repo root accordingly.

Releases run from packages/driver (root `pnpm release` delegates). The
changelog still lives in the docs app, so the release scripts reach it
via ../../../apps/docs and the after:bump hook stages it explicitly —
release-it no longer sits above both directories.

The merged workspace settings keep sharp unbuilt on purpose (prebuilt
binaries; building from source needs node-gyp and fails) — the docs app
had this right and the playground setting was the accident. postcss and
postcss-scss were unreferenced devDependencies and are dropped; prettier
moves to the root as the only shared tool.
2026-07-16 19:45:23 +01:00
Kamran Ahmed d3dc73a47f Set state.popover before onPopoverRender fires
Adversarial review of the primitive refactor caught a within-contract
regression: the old renderPopover committed the popover to state and
then ran onPopoverRender, so hooks reading opts.state.popover saw the
freshly rendered popover. After the refactor the state write happened
once the primitive returned — inside the hook, opts.state.popover was
undefined on first render and the previous step's detached popover on
transitions. Commit the state in the onRender adapter, before the user
hook, and pin it with a test.
2026-07-16 19:24:34 +01:00
Kamran Ahmed d4c5182ee6 Migrate the package build to tsdown
One tool replaces four: both vite lib configs, vite-plugin-dts,
api-extractor and the terser postbuild. tsdown covers each of their jobs
natively — per-entry declaration bundling (from the actual lib entry, so
the vite-plugin-dts types-field footgun is structurally gone), oxc
minification, and CSS extraction with @import inlining via @tsdown/css.

The config keeps the two-isolated-builds decision as a config array: a
single multi-entry build would still split the shared popover primitive
into a common chunk and merge the stylesheets. Filenames, the exports
map and the CDN globals (window["driver"]["js"].driver, driverHints)
are unchanged; attw/publint stay green across node10/node16/bundler for
both entries.

Verified against the previous pipeline's output: identical file list,
identical driver.css rule set, hints.css differs only in Lightning CSS
keeping the inset shorthand our source already uses (baseline everywhere
driver.js supports), and every artifact's gzip size is equal or smaller.
Build drops from ~6.8s to ~2.2s — three TypeScript passes down to one
plus tsdown's per-entry declaration emit.

The postbuild shrinks to the two plain .d.ts copies node10 resolution
needs. vitest config moves to vitest.config.ts (vite itself is no longer
a direct dependency), and a local *.css module declaration replaces
vite/client's ambient types.
2026-07-16 18:59:15 +01:00
Kamran Ahmed 18e9befbd2 Default the hint beacon to indigo
The beacon dot defaulted to the popover ink (#2d2d2d), which is nearly
invisible on a dark page. Default to indigo (#4f46e5) instead — it reads
on both light and dark grounds. Still overridable with
--driver-hint-color.
2026-07-16 18:42:18 +01:00
Kamran Ahmed 2a900ad497 Add hints examples to the playground
Four examples under a new Hints group: basic beacons, the twelve beacon
anchor points, localStorage-backed dismissal persistence, and hints
coexisting with a tour (with a Take the tour button added through a hint
popover's onPopoverRender).

The playground imports the library from source, so driver.js/hints is
aliased to src/hints.ts in both the astro config and tsconfig. The
subpath alias is declared before the driver.js one because aliases match
on prefix.
2026-07-16 18:24:50 +01:00
Kamran Ahmed 15da6817e4 Share the popover CSS between the tour and hints entries
The popover styling moves to src/popover.css, which both driver.css and
hints.css @import. Vite inlines the import at build time, so each entry's
stylesheet is self-contained: driver.css keeps the same rule set it had
before (verified against master — identical set, just regrouped), and
hints.css now carries the popover rules too.

This closes a gap the playground surfaced: hints.css previously held only
the beacon styles, so a hints-only consumer importing it got an unstyled
popover. Now importing hints.css is all they need. Consumers of both
entries ship the popover rules twice (~0.6KB gzip), which is harmless
since the two copies are identical.

custom-buttons.test.ts injected driver.css raw to assert the footer button
computed styles; jsdom doesn't follow @import, so it now injects
popover.css, where those rules live.
2026-07-16 18:24:43 +01:00
Kamran Ahmed 630adda553 Ship hints as the driver.js/hints entry
Two separate vite runs rather than one multi-entry build. Multi-entry
splits the shared popover primitive into a chunk, which would make the
tour bundle depend on a second file and cost every existing user bytes
for a feature they may never use; it also merged both stylesheets into
driver.css. Standing the entries alone keeps driver.css byte-identical
to master and the tour bundle within ~120 bytes of it, and lets hints be
used without the tour. Importing both duplicates the primitive (~2KB
gzip), which is safe because the copies only handle their own popovers.

The hints run writes to dist-hints/ and the postbuild folds it into
dist/. That indirection is not incidental: vite-plugin-dts takes its
entry from package.json's `types` field when bundling, not from the lib
entry, so pointing it at hints emits the tour's API under the hints name
and overwrites dist/driver.js.d.ts. api-extractor rolls up the hints
declarations from an explicit entry instead.

hints/package.json is a resolution shim for legacy node10, which predates
`exports`; attw is green across node10, node16 ESM/CJS and bundler for
both entries. sideEffects marks only CSS, so bundlers can drop unused
code from either entry.

Sizes (gzip): tour 6.7KB unchanged in CSS and ~6.8KB in JS, hints 4.2KB
JS + 0.4KB CSS standalone.
2026-07-15 04:27:53 +01:00
Kamran Ahmed 71a70682b9 Add the hints module
A standalone hints() factory: a pulsing beacon per element that opens a
popover when clicked. Independent of the tour — no overlay, no body
class, no shared state — so the page stays interactive and hints can be
used without a tour at all.

The popover is the primitive extracted in the previous commit, anchored
to the beacon rather than the element, which keeps the arrow pointing at
the dot without any new positioning code.

Closing and dismissing are separate: an outside click, Escape or a second
click on the beacon closes the popover and keeps the beacon, while the
Got it button dismisses the hint. onDismiss plus stable ids is the
persistence hook; storage stays in userland.

Tour interplay needs no coupling in either direction. The tour already
marks the body while it runs, so CSS hides the beacons and a body-class
observer closes an open hint. Nothing to register, and it works with any
driver instance.

Beacons are real buttons (focus, Enter/Space, ARIA for free), centered on
one of the twelve anchor points of the element's box by CSS, sized and
coloured through custom properties. An IntersectionObserver hides a
beacon whose element scrolls out of view, and scroll is captured so
nested containers reposition too.
2026-07-15 04:18:33 +01:00
Kamran Ahmed 1a4484e0d3 Extract the popover into a tour-agnostic primitive
popover.ts and position.ts no longer reach into the driver context.
renderPopover/repositionPopover now take an anchor element plus fully
resolved options and return the PopoverDOM to the caller, so nothing
below them reads config or state.

The tour-specific resolution moves into the new step-popover.ts: the
step-then-config-then-default fallback chains, done-step detection, the
DriverHook adapters for the button clicks and the dummy-element
centering. driver.ts and highlight.ts drive the primitive through it,
and bringInView takes a smoothScroll flag instead of the context.

Behaviour is unchanged. The focus special-case for the dummy element
went away rather than being ported: it tested for a class that is never
set (the dummy element only gets an id), so the branch was always false
and the anchor was always scanned for focusable elements.

This is the seam the upcoming hints entry renders its popovers through.
It costs the tour ~137 bytes gzip for the resolved-options indirection.
2026-07-15 04:18:12 +01:00
Kamran Ahmed 6c486ecd17 Pin popover placement and config-fallback behavior in tests
Characterization tests ahead of extracting the popover into a
tour-agnostic primitive: exact box placement per side/align including
the stagePadding/popoverOffset arithmetic, the left-first side
fallback order, detached placements, config fallback chains, the
allowClose button filter, the ARIA contract and the popover state
exposure.
2026-07-15 04:16:29 +01:00
Kamran Ahmed b7d671c81e 1.7.0 1.7.0 2026-07-14 00:11:57 +01:00
Kamran Ahmed 82d51716d2 Add config to skip missing elements 2026-07-13 23:02:30 +01:00
Kamran Ahmed 1eb6c7853f Fix popover icon fonts and expose font-family variable 2026-07-12 02:57:40 +01:00
Kamran Ahmed a4f86e4304 Expose active step index on hook options 2026-07-12 02:09:57 +01:00
Kamran Ahmed 1910fb2c30 Minify the ESM bundle with Terser in postbuild 2026-07-08 03:38:26 +01:00
Kamran Ahmed cbf719f87e Fix postbuild esbuild resolution by using Vite 2026-07-08 03:33:40 +01:00
Kamran Ahmed c30fc8ec07 Document the multi-instance support 2026-07-08 03:24:49 +01:00
Kamran Ahmed bf4ae7e492 Tighten comments across the per-instance changes 2026-07-08 02:04:39 +01:00
Kamran Ahmed a4d6dd00d8 Add changelog entry for per-instance isolation 2026-07-08 02:04:34 +01:00
Kamran Ahmed 803c33e22b Add multiple-instances example to the playground 2026-07-08 01:53:29 +01:00
Kamran Ahmed 8ccf77faa6 Minify the ESM bundle whitespace in postbuild 2026-07-06 21:03:11 +01:00
Kamran Ahmed f28d08bfb7 Scope config, state and emitter to each driver instance 2026-07-06 16:19:08 +01:00
Kamran Ahmed 16a3684f54 Add forward specs for per-instance isolation (#571) 2026-07-06 16:09:13 +01:00
Kamran Ahmed dab8de6b9c Add tests covering driver, overlay and popover branches 2026-07-06 16:08:15 +01:00
Kamran Ahmed ffbf6a41ad Modify header image URL in README
Updated the image URL in the header to include a version query parameter.
2026-06-27 02:49:34 +01:00
Kamran Ahmed 3505d7bc40 Add og image and favicon to docs 2026-06-27 02:47:34 +01:00
Kamran Ahmed 2ca41eee01 Update hero and examples in docs 2026-06-27 01:23:33 +01:00
Kamran Ahmed aa188e86fb Redesign trusted-by logos as borderless row with tooltips 2026-06-26 14:03:08 +01:00
Kamran Ahmed 5994e1e0ab Fix formatting issues in readme 2026-06-26 12:36:07 +01:00
Kamran Ahmed b294d7e767 Redesign landing page 2026-06-26 11:59:51 +01:00
Kamran Ahmed 2088df4a90 Switch release tooling from np to release-it
- Tag and commit use the unreleased version with no v prefix
- Move changelog Unreleased entries under the version on bump
- GitHub release notes are pulled from the changelog section
2026-06-25 18:07:16 +01:00
Kamran Ahmed 565757bfb0 1.6.0 1.6.0 2026-06-25 17:41:04 +01:00
Kamran Ahmed 98d2c52e40 Fix close button not working on highlight 2026-06-25 16:46:05 +01:00
Kamran Ahmed 0dfcdacceb Fix positioned highlighted elements get clipped #454 #563 2026-06-25 15:45:30 +01:00
Kamran Ahmed 2633c2f453 Add test harness for multi-driver usage feature 2026-06-25 14:44:50 +01:00
Kamran Ahmed 39f3377176 Fix broken build and wrong x link 2026-06-25 13:06:43 +01:00