@steppy/player 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/README.md +190 -2
  4. package/THIRD_PARTY_LICENSES.txt +158 -0
  5. package/dist/steppy-cursor-legacy.js +2 -0
  6. package/dist/steppy-cursor-legacy.js.map +1 -0
  7. package/dist/steppy-player.js +5419 -0
  8. package/dist/steppy-player.js.map +1 -0
  9. package/dist/steppy-tour.js +2164 -0
  10. package/dist/steppy-tour.js.map +1 -0
  11. package/dist/steppy-video.js +472 -0
  12. package/dist/steppy-video.js.map +1 -0
  13. package/dist/types/cursor/animator.d.ts +135 -0
  14. package/dist/types/cursor/types.d.ts +61 -0
  15. package/dist/types/i18n/ui-strings.d.ts +48 -0
  16. package/dist/types/index.d.ts +10 -0
  17. package/dist/types/interaction/positioning.d.ts +22 -0
  18. package/dist/types/manifest/content.d.ts +24 -0
  19. package/dist/types/manifest/index.d.ts +3 -0
  20. package/dist/types/manifest/parse.d.ts +23 -0
  21. package/dist/types/manifest/schema.d.ts +2895 -0
  22. package/dist/types/steppy-guide.d.ts +195 -0
  23. package/dist/types/templates/base-styles.d.ts +15 -0
  24. package/dist/types/templates/controls.d.ts +17 -0
  25. package/dist/types/templates/index.d.ts +23 -0
  26. package/dist/types/templates/inline.d.ts +10 -0
  27. package/dist/types/templates/overlay.d.ts +10 -0
  28. package/dist/types/templates/sidebar.d.ts +19 -0
  29. package/dist/types/templates/types.d.ts +76 -0
  30. package/dist/types/tour/api.d.ts +54 -0
  31. package/dist/types/tour/contract.d.ts +54 -0
  32. package/dist/types/tour/dom.d.ts +43 -0
  33. package/dist/types/tour/engine.d.ts +157 -0
  34. package/dist/types/tour/events.d.ts +42 -0
  35. package/dist/types/tour/host.d.ts +153 -0
  36. package/dist/types/tour/index.d.ts +15 -0
  37. package/dist/types/tour/layer.d.ts +16 -0
  38. package/dist/types/tour/loader.d.ts +70 -0
  39. package/dist/types/tour/resolver.d.ts +30 -0
  40. package/dist/types/tour/routes.d.ts +40 -0
  41. package/dist/types/tour/signature.d.ts +16 -0
  42. package/dist/types/tour/storage.d.ts +28 -0
  43. package/dist/types/tour/strings.d.ts +42 -0
  44. package/dist/types/tour/styles.d.ts +13 -0
  45. package/dist/types/tour/templates.d.ts +47 -0
  46. package/dist/types/tour/tracker.d.ts +45 -0
  47. package/dist/types/tour/triggers.d.ts +52 -0
  48. package/dist/types/tour/validate.d.ts +82 -0
  49. package/dist/types/ui/markdown.d.ts +58 -0
  50. package/dist/types/ui/names.d.ts +18 -0
  51. package/dist/types/ui/placement.d.ts +59 -0
  52. package/dist/types/ui/strings.d.ts +31 -0
  53. package/dist/types/ui/tokens.d.ts +57 -0
  54. package/package.json +70 -4
  55. package/schema/README.md +19 -0
  56. package/schema/guide.schema.json +427 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * ``<steppy-guide>`` — Lit-based interactive guide player.
3
+ *
4
+ * Public API is HTML attributes + CustomEvents. See the Stage 1 design doc for
5
+ * the full contract. Implementation notes:
6
+ *
7
+ * - Manifest is fetched lazily when ``src`` is set; cached in ``manifest``
8
+ * state. ``parseManifest`` does both JSON parsing and Zod validation.
9
+ * - Coordinates flow capture-space → display-space at one point only:
10
+ * ``computeHotspotRect`` (which the cursor animator also uses via
11
+ * ``getDisplayScale``). Everything downstream — hotspot button, tooltip,
12
+ * cursor target — derives from the same scale, so resizes can never
13
+ * produce drift between cursor and hotspot.
14
+ * - The cursor / ripple / kbd elements live at a fixed position in the
15
+ * template so Lit's incremental render doesn't churn them; the animator
16
+ * refreshes its DOM refs once on connect.
17
+ * - Step progression is centralized in ``_advance`` and ``_playCurrentPosition``;
18
+ * the rest of the component is rendering.
19
+ */
20
+ import { LitElement, type PropertyValues } from 'lit';
21
+ import { type AnimatorOptions } from './cursor/animator.js';
22
+ import type { AnimatorFrame } from './cursor/types.js';
23
+ import { DEFAULT_UI_STRINGS, type UiStrings } from './i18n/ui-strings.js';
24
+ import type { CursorMode, TemplateMode } from './manifest/schema.js';
25
+ /** Animator-shaped subset the player actually calls. Tests can plug in a
26
+ * stub that skips real timing without owning the full CursorAnimator API. */
27
+ export interface AnimatorLike {
28
+ setTimings(t: Partial<import('./cursor/types.js').CursorTimings>): void;
29
+ setStage(stage: HTMLElement): void;
30
+ refreshDom(): void;
31
+ hide(): void;
32
+ abort(): void;
33
+ travelToTarget(frame: AnimatorFrame, targetIndex: number): Promise<void>;
34
+ playTargetAction(frame: AnimatorFrame, targetIndex: number): Promise<void>;
35
+ }
36
+ export declare class SteppyGuide extends LitElement {
37
+ /** Factory hook — overridden in tests to swap in a fast/no-op animator. */
38
+ static createAnimator: (opts: AnimatorOptions) => AnimatorLike;
39
+ static styles: import("lit").CSSResult[];
40
+ src: string;
41
+ locale: string | null;
42
+ variant: string | null;
43
+ autoplay: boolean;
44
+ startIndex: number;
45
+ /**
46
+ * Cursor presentation:
47
+ * - 'arrow' (default) animate the arrow + ripple/kbd; hotspot also pulses
48
+ * - 'hotspot' skip arrow/ripple/kbd; hotspot pulses and user still clicks
49
+ * - 'off' skip arrow + hotspot; auto-advance every step after waitAfter
50
+ * Unset (null) ⇒ fall back to manifest's `cursor.mode`, then 'arrow'.
51
+ */
52
+ cursor: CursorMode | null;
53
+ /**
54
+ * Presentation template (runtime-switchable viewer setting):
55
+ * - 'overlay' (default) floating callout pinned to the target
56
+ * - 'sidebar' left rail with a step timeline + description
57
+ * - 'inline' slim bottom caption bar
58
+ * Resolution: this attribute → persisted localStorage → manifest
59
+ * ``defaultTemplate`` → 'overlay'. Unknown strings fall through.
60
+ */
61
+ template: TemplateMode | null;
62
+ /** When set, suppress the built-in layout (variant) switcher so a host can
63
+ * own the control (the generated Angular toolbar / static page nav drives
64
+ * `variant` directly). The locale switcher is unaffected. */
65
+ hideLayoutSwitcher: boolean;
66
+ /** Sparse per-locale UI string overrides. Property-only (no attribute). */
67
+ uiStrings: Partial<Record<string, Partial<UiStrings>>> | undefined;
68
+ private manifest;
69
+ private loadError;
70
+ private currentStepIndex;
71
+ private currentFrameIndex;
72
+ private currentTargetIndex;
73
+ private waitingForInput;
74
+ private completed;
75
+ private missCount;
76
+ private hotspotRect;
77
+ private tooltipPlacement;
78
+ private stageSize;
79
+ /** Resolved presentation template the current render uses. */
80
+ private _activeTemplate;
81
+ /** The stage element the ResizeObserver/animator are currently bound to.
82
+ * Tracked so a template switch (which relocates the stage) re-attaches. */
83
+ private _observedStage;
84
+ /** Furthest step the user has reached. Used to gate ``goTo`` / ``prev``. */
85
+ private maxReachedStepIndex;
86
+ private animator;
87
+ private stageRef;
88
+ private imgRef;
89
+ private cursorRef;
90
+ private rippleRef;
91
+ private kbdRef;
92
+ private tooltipRef;
93
+ private resizeObserver;
94
+ private autoAdvanceTimer;
95
+ /** Token bumped on every ``_playCurrentPosition`` call so stale awaits drop. */
96
+ private playToken;
97
+ /** Resolved on the user's correct click; the running play awaits this. */
98
+ private waitForClick;
99
+ private resolveClick;
100
+ connectedCallback(): void;
101
+ disconnectedCallback(): void;
102
+ willUpdate(changed: PropertyValues): void;
103
+ updated(changed: PropertyValues): void;
104
+ /** Keep the current timeline row visible. The sidebar rail is height-capped
105
+ * and scrolls its timeline internally, so on a long guide ``next()`` would
106
+ * otherwise advance to a row below the fold. ``block: 'nearest'`` scrolls the
107
+ * minimum needed, which also means it does nothing when the row is already
108
+ * visible — including in the templates that have no timeline at all. */
109
+ private _scrollActiveRowIntoView;
110
+ /** Re-bind the ResizeObserver + animator to a relocated stage element (e.g.
111
+ * after a template switch) and reposition the hotspot/tooltip. Does not
112
+ * touch step state, so the in-flight play loop continues uninterrupted. */
113
+ private _reattachStage;
114
+ next(): void;
115
+ prev(): void;
116
+ restart(): void;
117
+ goTo(index: number): void;
118
+ private _loadManifest;
119
+ private _fallbackLayoutKey;
120
+ private _resolveVariant;
121
+ private _restartFromStart;
122
+ private _setupResizeObserver;
123
+ private _currentStep;
124
+ /**
125
+ * The `Capture` the active render reads from — screenshots AND caption.
126
+ *
127
+ * Both go through this one accessor on purpose: a step's text can be
128
+ * overridden per layout (the twin-branch pattern), so reading the frame from
129
+ * one layout and the wording from another would put "click the row of the
130
+ * table" above a screenshot of a card list.
131
+ */
132
+ private _captureFor;
133
+ private _contentFor;
134
+ private _currentFrame;
135
+ private _currentTargetBbox;
136
+ private _recomputeHotspot;
137
+ private _placeTooltip;
138
+ private _goToStep;
139
+ /** Resolve the effective cursor mode. Host attribute wins; manifest is the
140
+ * fallback; 'arrow' is the final default. Unknown attribute strings fall
141
+ * through to the manifest so a typo can't strand the player. */
142
+ private _effectiveCursorMode;
143
+ private _playCurrentPosition;
144
+ private _advance;
145
+ /** Idempotent: emits ``steppy:hotspot`` with target=correct and resolves the
146
+ * current wait. A second call is a no-op (the wait already advanced). */
147
+ private _confirmHotspotClick;
148
+ private _onStageClick;
149
+ private _onHotspotClick;
150
+ private _handleKeyDown;
151
+ private _onLocaleChange;
152
+ private _onVariantChange;
153
+ private _onImgLoad;
154
+ private _emit;
155
+ render(): import("lit-html").TemplateResult;
156
+ /** The live stage subtree (screenshot + cursor/ripple/kbd + hotspot +
157
+ * miss-toast), shared verbatim by every template via the ``renderStage``
158
+ * thunk so the refs + handlers stay bound to the component.
159
+ *
160
+ * A template *switch* swaps the whole top-level template, so Lit recreates
161
+ * the stage element. That is handled by ``updated`` → ``_reattachStage``
162
+ * (re-point the animator + ResizeObserver, recompute placement) WITHOUT
163
+ * resetting step state, so the in-flight animation survives the move. The
164
+ * floating tooltip is included only in overlay mode (sidebar and inline
165
+ * surface the description in their own chrome). */
166
+ private _renderStage;
167
+ private _renderHotspot;
168
+ private _renderTooltip;
169
+ private _renderMissToast;
170
+ /** Project the ordered manifest steps into presentation view models. Pure
171
+ * projection of engine state — no behavior, no duplicated gates. */
172
+ private _buildStepViews;
173
+ /** Display-only duration estimate (~8s/step). Never feeds the play loop. */
174
+ private _durationLabel;
175
+ private _buildTemplateContext;
176
+ /** The built-in template switcher routes through the reflected property so
177
+ * ``willUpdate`` re-resolves + persists (and hosts observe the attribute). */
178
+ private _onTemplateChange;
179
+ private static readonly TEMPLATE_STORAGE_KEY;
180
+ private _readPersistedTemplate;
181
+ private _persistTemplate;
182
+ /** Resolve the effective template: explicit ``template`` attribute →
183
+ * persisted localStorage → manifest ``defaultTemplate`` → 'overlay'.
184
+ * Unknown attribute strings fall through so a typo can't strand the player. */
185
+ private _resolveTemplate;
186
+ private _renderLoading;
187
+ private _renderError;
188
+ }
189
+ declare global {
190
+ interface HTMLElementTagNameMap {
191
+ 'steppy-guide': SteppyGuide;
192
+ }
193
+ }
194
+ export { DEFAULT_UI_STRINGS };
195
+ export type { UiStrings };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Shared player styles: design tokens, the screenshot stage + cursor/ripple/
3
+ * kbd/hotspot/tooltip, status/error blocks, and the shared chrome control
4
+ * primitives (buttons, selects, segmented control) every template composes.
5
+ *
6
+ * Design language: warm cream surfaces, near-black text, rust-orange accent,
7
+ * green for completed steps. Serif titles, sans body, mono meta/counters. All
8
+ * theming flows through CSS custom properties on ``:host`` so the player stays
9
+ * overridable; fonts use system stacks only (offline, no CDN).
10
+ *
11
+ * The historical engine variable names (``--steppy-hotspot-color`` etc.) are
12
+ * preserved and merely re-pointed at the new palette so existing host overrides
13
+ * keep working.
14
+ */
15
+ export declare const baseStyles: import("lit").CSSResult;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shared chrome fragments composed by the three templates. Pure functions over
3
+ * {@link TemplateContext} — no state, no engine logic. Each template arranges
4
+ * these into its own layout.
5
+ */
6
+ import { nothing, type TemplateResult } from 'lit';
7
+ import type { TemplateContext } from './types.js';
8
+ export declare function renderProgress(ctx: TemplateContext): TemplateResult;
9
+ /** Compact "i/n" counter (inline + sidebar footers). */
10
+ export declare function renderCounter(ctx: TemplateContext): TemplateResult;
11
+ export declare function renderPrev(ctx: TemplateContext): TemplateResult;
12
+ export declare function renderNext(ctx: TemplateContext): TemplateResult;
13
+ export declare function renderRestart(ctx: TemplateContext): TemplateResult;
14
+ export declare function renderLocaleSelect(ctx: TemplateContext): TemplateResult | typeof nothing;
15
+ export declare function renderLayoutSelect(ctx: TemplateContext): TemplateResult | typeof nothing;
16
+ /** Segmented [Sidebar | Overlay | Inline] control (active = dark fill). */
17
+ export declare function renderTemplateSwitcher(ctx: TemplateContext): TemplateResult;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Template registry. The component dispatches ``render()`` to one of these by
3
+ * the resolved ``template`` id; ``static styles`` aggregates every template's
4
+ * CSS (unrendered templates simply have no matching DOM).
5
+ */
6
+ import type { TemplateId, TemplateModule } from './types.js';
7
+ /**
8
+ * The registry is the single source of truth: registering a template here is
9
+ * the only edit needed inside this file. `ALL_TEMPLATES`, `isTemplateId` and
10
+ * `templateStyles` are all derived from it below, so a new template can never
11
+ * be renderable-but-unstyled or renderable-but-unlistable.
12
+ */
13
+ export declare const TEMPLATES: Record<TemplateId, TemplateModule>;
14
+ /**
15
+ * Display/selection order for the segmented switcher — deliberately not the
16
+ * registry's declaration order, which is why this one list stays explicit.
17
+ * `templates.test.ts` asserts it covers every registered template.
18
+ */
19
+ export declare const ALL_TEMPLATES: readonly TemplateId[];
20
+ export declare function isTemplateId(value: unknown): value is TemplateId;
21
+ /** Aggregated styles for the component's ``static styles``. */
22
+ export declare const templateStyles: import("lit").CSSResult[];
23
+ export type { TemplateContext, TemplateId, StepView, TemplateModule } from './types.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Inline template — full-bleed preview with a slim full-width caption bar: the
3
+ * step counter, the current localized description, a mono sub-label, and
4
+ * prev/next. The switchers ride along compactly so the player stays
5
+ * self-contained, but the bar is the only chrome over the preview.
6
+ */
7
+ import { type TemplateResult } from 'lit';
8
+ import type { TemplateContext } from './types.js';
9
+ export declare function render(ctx: TemplateContext): TemplateResult;
10
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Overlay template — the original/default player presentation: a full-bleed
3
+ * screenshot stage with a floating callout pinned to the highlighted target,
4
+ * and a bottom chrome bar. Lifted from the component verbatim (only the new
5
+ * template switcher is added); engine logic is untouched.
6
+ */
7
+ import { type TemplateResult } from 'lit';
8
+ import type { TemplateContext } from './types.js';
9
+ export declare function render(ctx: TemplateContext): TemplateResult;
10
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Sidebar template — a fixed left rail (guide title, meta line, vertical step
3
+ * timeline, current-step description, prev/next + counter) beside the preview.
4
+ * The current step's full localized description is surfaced in the rail; the
5
+ * in-stage floating tooltip is suppressed (the stage handles that based on the
6
+ * active template). Collapses to a single column on narrow containers.
7
+ *
8
+ * The rail is height-capped and the timeline scrolls inside it, so a 19-step
9
+ * guide occupies the same vertical space as a 3-step one. The component pairs
10
+ * this with ``_scrollActiveRowIntoView`` so advancing never leaves the current
11
+ * step off-screen. Every layout dimension the cap touches — rail width, rail
12
+ * height, sticky offset — is a ``--steppy-*`` custom property, because a host
13
+ * that embeds the player under its own chrome (the Angular target) cannot use
14
+ * the ``100vh`` default.
15
+ */
16
+ import { type TemplateResult } from 'lit';
17
+ import type { TemplateContext } from './types.js';
18
+ export declare function render(ctx: TemplateContext): TemplateResult;
19
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Engine → template contract.
3
+ *
4
+ * The engine (the ``<steppy-guide>`` component) owns ALL state and behavior:
5
+ * manifest, step indices, cursor animation, hotspot/tooltip placement,
6
+ * navigation, i18n, persistence. A *template* is a pure render function over an
7
+ * immutable {@link TemplateContext} — it decides only where the chrome lives and
8
+ * how it looks. Templates never hold step state and never re-implement engine
9
+ * gates; everything they need (including derived values like step ``status`` and
10
+ * disabled flags) is precomputed on the context.
11
+ *
12
+ * Anything that needs a live DOM ref — the screenshot stage with its
13
+ * cursor/ripple/kbd/hotspot, and the overlay's floating callout — is supplied as
14
+ * the {@link TemplateContext.renderStage} thunk, which the component owns so the
15
+ * ``ref()`` directives and event handlers stay bound to it across template
16
+ * switches.
17
+ */
18
+ import type { CSSResult, TemplateResult } from 'lit';
19
+ import type { UiStrings } from '../i18n/ui-strings.js';
20
+ import type { TemplateMode } from '../manifest/schema.js';
21
+ export type TemplateId = TemplateMode;
22
+ /** A single step projected for presentation. Pure projection of engine state —
23
+ * no behavior, no duplicated gates. */
24
+ export interface StepView {
25
+ /** 1-based step index (matches the manifest ``step.index``). */
26
+ index: number;
27
+ /** Short heading (sidebar timeline). Falls back to the description. */
28
+ title: string;
29
+ /** Full localized instruction body (the manifest ``text``). */
30
+ description: string;
31
+ /** Mono meta sub-label (the manifest ``subtitle``). May be empty. */
32
+ subLabel: string;
33
+ /** Position relative to the current step. */
34
+ status: 'completed' | 'current' | 'upcoming';
35
+ /** True when the step is reachable via ``goTo`` (index ≤ furthest reached). */
36
+ reachable: boolean;
37
+ }
38
+ export interface TemplateContext {
39
+ steps: readonly StepView[];
40
+ /** 1-based index of the current step. */
41
+ currentIndex: number;
42
+ total: number;
43
+ /** Localized, display-only duration estimate (e.g. "~3 min"). */
44
+ durationLabel: string;
45
+ /** Localized guide title for the current locale. */
46
+ guideTitle: string;
47
+ locale: string;
48
+ ui: UiStrings;
49
+ waitingForInput: boolean;
50
+ completed: boolean;
51
+ onNext: () => void;
52
+ onPrev: () => void;
53
+ onRestart: () => void;
54
+ /** Jump to a 1-based step index (engine gates to reachable steps). */
55
+ onGoTo: (index1: number) => void;
56
+ prevDisabled: boolean;
57
+ nextDisabled: boolean;
58
+ locales: readonly string[];
59
+ layouts: readonly string[];
60
+ templates: readonly TemplateId[];
61
+ activeTemplate: TemplateId;
62
+ activeLocale: string;
63
+ activeLayout: string | null;
64
+ hideLayoutSwitcher: boolean;
65
+ onLocaleChange: (ev: Event) => void;
66
+ onLayoutChange: (ev: Event) => void;
67
+ onTemplateChange: (t: TemplateId) => void;
68
+ /** The ``.steppy-stage`` subtree (img + cursor + ripple + kbd + hotspot +
69
+ * miss-toast, and the floating tooltip in overlay mode). Carries the live
70
+ * refs + handlers; identical element shape in every template. */
71
+ renderStage: () => TemplateResult;
72
+ }
73
+ export interface TemplateModule {
74
+ render(ctx: TemplateContext): TemplateResult;
75
+ styles: CSSResult;
76
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The public surface of ``<steppy-tour-host>`` — what an app (or a
3
+ * framework adapter) programs against.
4
+ */
5
+ import type { TourSource } from './loader.js';
6
+ import type { TourStringOverrides } from './strings.js';
7
+ export type { TourSource } from './loader.js';
8
+ export type { TourStringOverrides } from './strings.js';
9
+ export interface TourStartOptions {
10
+ /** Route parameters for the tour's entry (``/invoices/:invoiceId``). */
11
+ params?: Record<string, string | number>;
12
+ /** Start at this step id instead of the first. */
13
+ step?: string;
14
+ }
15
+ export interface TourPosition {
16
+ tourId: string;
17
+ stepId: string;
18
+ /** 0-based among the steps that apply to the current layout. */
19
+ index: number;
20
+ total: number;
21
+ }
22
+ export interface TourNavigateContext {
23
+ /** The same path relative to ``<base href>`` — what a client-side router wants. */
24
+ appPath: string;
25
+ tourId: string;
26
+ }
27
+ /**
28
+ * Navigate the app to a tour's entry (or a route linked from step text).
29
+ * ``path`` is the document path, base included. Default: ``location.assign``.
30
+ * A returned promise is awaited (its value is ignored); a rejection fails the
31
+ * start with ``entry-params``. Router calls fit as they are:
32
+ * ``(_, { appPath }) => router.navigateByUrl(appPath)``.
33
+ */
34
+ export type TourNavigate = (path: string, ctx: TourNavigateContext) => void | PromiseLike<unknown>;
35
+ export interface TourHostApi {
36
+ manifest: string;
37
+ fallbackManifest: string;
38
+ buildId: string;
39
+ locale: string;
40
+ guideOrigin: string;
41
+ baseZIndex: number;
42
+ targetTimeout: number;
43
+ disabled: boolean;
44
+ source: TourSource | null;
45
+ navigate: TourNavigate | null;
46
+ strings: TourStringOverrides | undefined;
47
+ /** Start a tour. Resolves true once it started; never rejects. */
48
+ start(tourId: string, options?: TourStartOptions): Promise<boolean>;
49
+ stop(reason?: string): void;
50
+ /** Advance the current step, whatever its kind. */
51
+ next(): void;
52
+ readonly isActive: boolean;
53
+ readonly current: TourPosition | null;
54
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * In-app tour data contract v1, the TypeScript twin of ``src/steppy/tour_spec.py``.
3
+ *
4
+ * The overlay validates every manifest and tour file against these values
5
+ * (``validate.ts``); the compiler never emits anything they reject.
6
+ * ``tests/test_tour_contract_sync.py`` keeps both sides equal, so every value
7
+ * stays a plain literal: string patterns carry no backslashes, and arrays are
8
+ * written on one line.
9
+ */
10
+ export declare const TOUR_SCHEMA_VERSION = 1;
11
+ export declare const ADVANCE_KINDS: readonly ["click", "input", "change", "visible", "manual"];
12
+ export declare const TARGETED_ADVANCE_KINDS: readonly ["click", "input", "change", "visible"];
13
+ export declare const PLACEMENTS: readonly ["top", "bottom", "left", "right", "auto"];
14
+ export declare const TOUR_EVENTS: readonly ["tour-start", "tour-step", "tour-complete", "tour-dismiss", "tour-offpath", "tour-error"];
15
+ export declare const TOUR_ERROR_REASONS: readonly ["target-timeout", "entry-params", "load-failed", "schema-unsupported", "invalid-data"];
16
+ export declare const TOUR_PARTS: readonly ["layer", "spotlight", "bubble", "title", "body", "progress", "button", "primary", "secondary", "next", "close", "skip", "end", "resume", "pill", "guide-link"];
17
+ export declare const ATTR_TOUR_ID = "data-tour-id";
18
+ export declare const ATTR_STEP_ID = "data-step-id";
19
+ export declare const ATTR_STATE = "data-state";
20
+ export declare const ATTR_ADVANCE = "data-advance";
21
+ export declare const BUBBLE_STATES: readonly ["shown", "fallback"];
22
+ /** Languages ``strings.ts`` ships chrome strings for; others need the host's ``strings``. */
23
+ export declare const CHROME_STRING_LOCALES: readonly ["en", "fr", "nl", "de"];
24
+ export declare const TEST_ID_PATTERN = "^[A-Za-z0-9_.:/-]{1,128}$";
25
+ export declare const STEP_ID_PATTERN = "^[A-Za-z0-9_.:/-]{1,128}$";
26
+ export declare const TEST_ID_ATTRIBUTE_PATTERN = "^data-[a-z0-9-]+$";
27
+ export declare const TOUR_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$";
28
+ export declare const LAYOUT_NAME_PATTERN = "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$";
29
+ export declare const ROLE_PATTERN = "^[A-Za-z0-9_-]{1,64}$";
30
+ export declare const LOCALE_PATTERN = "^[A-Za-z]{2,3}(?:[-_][A-Za-z0-9]{1,8}){0,5}$";
31
+ export declare const SRI_PATTERN = "^sha384-[A-Za-z0-9+/]{64}$";
32
+ export declare const TOUR_FILE_NAME_PATTERN = "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}[.][A-Za-z0-9_-]{1,64}[.]json$";
33
+ export declare const ROUTE_PATTERN = "^/$|^(?:/(?::[A-Za-z_][A-Za-z0-9_]{0,63}|[A-Za-z0-9._~%!$&()*+,;=@-]{1,128})){1,32}$";
34
+ export declare const MEDIA_QUERY_PATTERN = "^[A-Za-z0-9 :().,<>=/_-]{1,256}$";
35
+ export declare const BUILD_ID_PATTERN = "^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9])?$";
36
+ export declare const MAX_TOURS = 500;
37
+ export declare const MAX_STEPS = 100;
38
+ export declare const MAX_LOCALES = 32;
39
+ export declare const MAX_LAYOUTS = 16;
40
+ export declare const MAX_TITLE_CHARS = 200;
41
+ export declare const MAX_TEXT_CHARS = 2000;
42
+ export declare const MAX_ROUTE_CHARS = 512;
43
+ export declare const MAX_URL_CHARS = 2048;
44
+ export declare const MAX_MEDIA_QUERY_CHARS = 256;
45
+ export declare const MAX_TOUR_FILE_BYTES = 262144;
46
+ export declare const MAX_MANIFEST_BYTES = 1048576;
47
+ /** Player-only defaults (no Python twin). */
48
+ export declare const DEFAULT_TARGET_TIMEOUT_MS = 8000;
49
+ export declare const DEFAULT_BASE_Z_INDEX = 2147483000;
50
+ export type AdvanceKind = (typeof ADVANCE_KINDS)[number];
51
+ export type Placement = (typeof PLACEMENTS)[number];
52
+ export type TourEventName = (typeof TOUR_EVENTS)[number];
53
+ export type TourErrorReason = (typeof TOUR_ERROR_REASONS)[number];
54
+ export type TourPart = (typeof TOUR_PARTS)[number];
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Everything the overlay asks the browser about geometry and timing, behind
3
+ * one interface. ``defaultDom`` is the real thing; tests swap
4
+ * ``SteppyTourHost.dom`` for a stub with settable rects and a manual
5
+ * scheduler (happy-dom has no layout, and its rAF escapes fake timers).
6
+ */
7
+ import { type Rect } from '../ui/placement.js';
8
+ export interface Scheduler {
9
+ now(): number;
10
+ raf(cb: () => void): number;
11
+ cancelRaf(id: number): void;
12
+ setTimeout(cb: () => void, ms: number): number;
13
+ clearTimeout(id: number): void;
14
+ setInterval(cb: () => void, ms: number): number;
15
+ clearInterval(id: number): void;
16
+ }
17
+ export interface Viewport {
18
+ x: number;
19
+ y: number;
20
+ width: number;
21
+ height: number;
22
+ }
23
+ export interface DomAdapter {
24
+ scheduler: Scheduler;
25
+ /** The element's effective rect (see ``effectiveRect``), or null when it has none. */
26
+ rect(el: Element): Rect | null;
27
+ isVisible(el: Element): boolean;
28
+ /** The visual viewport, in layout-viewport coordinates. */
29
+ viewport(): Viewport;
30
+ matchMedia(query: string): boolean;
31
+ reducedMotion(): boolean;
32
+ scrollIntoView(el: Element, instant: boolean): void;
33
+ supportsPopover(): boolean;
34
+ }
35
+ /**
36
+ * Playwright's notion of a visible box, extended for wrapper hosts: an element
37
+ * with ``display: contents`` measures as the union of its children, and an
38
+ * empty 0x0 host (a custom element wrapping a native control) as its first
39
+ * visible focusable descendant.
40
+ */
41
+ export declare function effectiveRect(el: Element, depth?: number): Rect | null;
42
+ export declare const defaultScheduler: Scheduler;
43
+ export declare const defaultDom: DomAdapter;