@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,45 @@
1
+ /**
2
+ * Keeps the spotlight on the target and the bubble next to it while a step is
3
+ * shown. Geometry is written through CSSOM custom properties only (no
4
+ * ``style=`` attributes, which a strict CSP blocks).
5
+ *
6
+ * Driven by capture-phase scroll (which catches scrolling ancestors), resize,
7
+ * the visual viewport, ResizeObserver and a slow poll; ``notify`` coalesces
8
+ * them into one placement per frame. A target that got detached or hidden is
9
+ * re-found by id first; only when that fails is the step reported lost.
10
+ *
11
+ * Invariant: the bubble never covers the spotlight when a side has room for
12
+ * it; otherwise it becomes a sheet at the top or bottom of the viewport, away
13
+ * from the target's centre (where a click lands). A step with nothing to point
14
+ * at is centred, unless that would cover an open app dialog: such a step is
15
+ * usually about the dialog (a confirmation), so it becomes a sheet instead.
16
+ */
17
+ import { type Rect, type TooltipSide } from '../ui/placement.js';
18
+ import type { DomAdapter } from './dom.js';
19
+ export declare const SPOT_PAD = 6;
20
+ export declare const GAP = 10;
21
+ export declare const MARGIN = 8;
22
+ export declare const SHEET_BELOW = 640;
23
+ export interface TrackerOptions {
24
+ dom: DomAdapter;
25
+ layer: () => HTMLElement | null;
26
+ bubble: () => HTMLElement | null;
27
+ /** The current target, or null for a centred (targetless) step. */
28
+ target: () => Element | null;
29
+ /** Re-find the target by id after it was detached or hidden. */
30
+ refind: () => Element | null;
31
+ preferred: () => TooltipSide | 'auto';
32
+ /** A rect the bubble should not cover when it has a choice (the next step's target). */
33
+ avoid: () => Rect | null;
34
+ /** The app's open dialogs, which a centred bubble moves off. */
35
+ dialogs?: () => Rect[];
36
+ onLost: () => void;
37
+ /** The bubble was placed (it is visible from now on, so it can take focus). */
38
+ onPlaced?: () => void;
39
+ }
40
+ export interface Tracker {
41
+ start(): void;
42
+ stop(): void;
43
+ notify(): void;
44
+ }
45
+ export declare function createTracker(o: TrackerOptions): Tracker;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Turns what the user does *in the app* into engine events: document-level
3
+ * capture listeners that never stop or alter the app's own events.
4
+ *
5
+ * - A click whose path holds the current step's test-id advances a ``click``
6
+ * step; a click on a *later* step's target jumps there (performed when that
7
+ * step is itself a click step). The resume record is written synchronously,
8
+ * before any navigation the click may cause; the engine is told on the next
9
+ * task so the app's handlers run first.
10
+ * - ``input`` / ``change`` on an ``input`` step's target enable Next / commit.
11
+ * - Any interaction outside the overlay arms a ``change`` step's watcher.
12
+ * - Escape dismisses the tour unless the app is using it (a dialog, an open
13
+ * popup, ``preventDefault``, an IME composition).
14
+ *
15
+ * Events whose path goes through the overlay are its own UI and are ignored.
16
+ * Untrusted (scripted) events count like trusted ones: the CI replay clicks
17
+ * with synthetic events.
18
+ */
19
+ import type { EngineEvent, EngineState } from './engine.js';
20
+ export interface TriggerContext {
21
+ host: HTMLElement;
22
+ attr: string;
23
+ state(): EngineState;
24
+ dispatch(e: EngineEvent): void;
25
+ /** The current step's resolved target. */
26
+ target(): Element | null;
27
+ /** Called synchronously when a click advances or jumps: persist the next step. */
28
+ persistAhead(fromIndex: number): void;
29
+ /** Any interaction outside the overlay (arms ``change`` watchers). */
30
+ interacted(): void;
31
+ /** A ``change`` event or a document click: re-check a ``change`` step. */
32
+ tick(): void;
33
+ defer(cb: () => void): void;
34
+ }
35
+ /** An app dialog: Escape inside one is the app's, and a centred bubble moves off an open one. */
36
+ export declare const APP_DIALOG = "dialog,[role=dialog],[role=alertdialog],[aria-modal=\"true\"]";
37
+ export declare function attachTriggers(ctx: TriggerContext): () => void;
38
+ /**
39
+ * Watches a ``change`` step: the value signature is sampled until the user
40
+ * first interacts (so a label the app fills in asynchronously is not taken
41
+ * for a change), then any difference — ignored while a popup is open, since
42
+ * the signature of an open dropdown is not a choice — advances the step.
43
+ */
44
+ export declare function watchChange(target: Element, signature: (el: Element) => string, onChange: () => void, schedule: {
45
+ raf(cb: () => void): number;
46
+ setInterval(cb: () => void, ms: number): number;
47
+ clearInterval(id: number): void;
48
+ }): {
49
+ arm(): void;
50
+ tick(): void;
51
+ stop(): void;
52
+ };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The overlay's security boundary: every manifest and tour file is validated
3
+ * here before anything renders, and a file that breaks any rule is rejected
4
+ * whole (spec 7.1). Hand-written rather than zod so the tour bundle stays small.
5
+ *
6
+ * Only known keys are copied into fresh objects — unknown keys are ignored, so
7
+ * a newer producer's extra field never breaks an older overlay — but unknown
8
+ * enum values and an unknown schema major are rejected: a tour file is data,
9
+ * never code. The rules mirror ``src/steppy/contracts/tours.py`` (the
10
+ * producer's self-check); ``contracts/fixtures/tours/cases.json`` runs both
11
+ * sides over the same cases.
12
+ */
13
+ import { type AdvanceKind, type Placement } from './contract.js';
14
+ export interface TourEntry {
15
+ readonly route: string;
16
+ }
17
+ export interface ManifestTour {
18
+ readonly id: string;
19
+ readonly role: string;
20
+ readonly title: Readonly<Record<string, string>>;
21
+ readonly entry: TourEntry | null;
22
+ readonly steps: number;
23
+ readonly files: Readonly<Record<string, string>>;
24
+ readonly integrity: Readonly<Record<string, string>>;
25
+ }
26
+ export interface TourManifest {
27
+ readonly buildId: string;
28
+ readonly defaultLocale: string;
29
+ readonly locales: readonly string[];
30
+ readonly testIdAttribute: string;
31
+ readonly guideOrigin: string | null;
32
+ readonly layouts: Readonly<Record<string, string>> | null;
33
+ readonly tours: readonly ManifestTour[];
34
+ }
35
+ export interface TourStep {
36
+ readonly id: string;
37
+ readonly target: string | null;
38
+ readonly advance: AdvanceKind;
39
+ readonly waitFor: string | null;
40
+ readonly title: string | null;
41
+ readonly text: string | null;
42
+ readonly placement: Placement | null;
43
+ readonly layouts: readonly string[] | null;
44
+ }
45
+ export interface TourFile {
46
+ readonly id: string;
47
+ readonly buildId: string;
48
+ readonly locale: string;
49
+ readonly title: string;
50
+ readonly guideUrl: string | null;
51
+ readonly entry: TourEntry | null;
52
+ readonly steps: readonly TourStep[];
53
+ }
54
+ export interface Issue {
55
+ path: string;
56
+ message: string;
57
+ }
58
+ export type FailReason = 'invalid-data' | 'schema-unsupported' | 'load-failed';
59
+ export type Result<T> = {
60
+ ok: true;
61
+ value: T;
62
+ } | {
63
+ ok: false;
64
+ reason: FailReason;
65
+ issues: Issue[];
66
+ };
67
+ /** A same-origin, base-relative route pattern (``/invoices/:invoiceId``). */
68
+ export declare function isRoutePattern(value: unknown): value is string;
69
+ export declare function isBuildId(value: unknown): value is string;
70
+ /** ``scheme://host[:port]`` of an absolute http(s) URL without credentials, else null. */
71
+ export declare function httpOrigin(value: string): string | null;
72
+ /** Parse JSON text; an HTML body (an SPA fallback page) is a load failure, not bad data. */
73
+ export declare function parseJson(text: string): Result<unknown>;
74
+ export declare function validateManifest(raw: unknown): Result<TourManifest>;
75
+ export interface TourContext {
76
+ manifest: TourManifest;
77
+ entry: ManifestTour;
78
+ locale: string;
79
+ /** The guide origin this overlay trusts for ``guideUrl`` (null: none). */
80
+ guideOrigin: string | null;
81
+ }
82
+ export declare function validateTour(raw: unknown, ctx: TourContext): Result<TourFile>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Inline-markdown renderer shared by the guide player and the in-app tour
3
+ * overlay.
4
+ *
5
+ * Mirrors the inline subset of the server-side ``markdown-it`` ``renderInline``
6
+ * filter (``src/steppy/guide.py``, configured ``{html:false, breaks:true,
7
+ * linkify:true}``) used by the step-by-step guide, so the interactive player
8
+ * renders the same content the static guide does:
9
+ *
10
+ * - **bold** / __bold__ , *italic* / _italic_ (recursive — emphasis nests)
11
+ * - `inline code`
12
+ * - [label](url) links — label is parsed recursively
13
+ * - autolinked bare URLs (``https://…`` / ``www.…``) and emails (linkify)
14
+ * - hard line breaks: every ``\n`` becomes ``<br>`` (``breaks:true``)
15
+ *
16
+ * The manifest carries raw text (it is reused for ``alt``/``aria-label``
17
+ * attributes, where HTML must not appear), so emphasis is rendered here, on the
18
+ * client, only at the visible display sites.
19
+ *
20
+ * Returns an array of literal-string + Lit ``TemplateResult`` parts, meant to be
21
+ * interpolated into an existing parent element (``${renderInlineMarkdown(text)}``,
22
+ * the same shape as ``${items.map(...)}``). Literal text and ``href`` values stay
23
+ * auto-escaped by Lit, and which link URLs become links is decided by a
24
+ * ``LinkPolicy`` — so it is XSS-safe by construction, with no ``unsafeHTML``.
25
+ *
26
+ * Link policies: the guide keeps its historical set (http/https/mailto, a
27
+ * site-relative path, an anchor) minus protocol-relative ``//host`` and
28
+ * ``/\host``, which browsers resolve to another origin. The tour overlay passes
29
+ * a stricter policy of its own (same-origin routes and the guide origin only,
30
+ * no autolinks). A URL the policy refuses leaves the whole ``[label](url)``
31
+ * literal, exactly as an unmatched link always rendered.
32
+ *
33
+ * Scope is intentionally inline-only (no block constructs — ``renderInline`` does
34
+ * not render lists/headings/blockquotes either, so there is no parity gap). The
35
+ * regex emphasis rule is not markdown-it's full delimiter-run algorithm, so a few
36
+ * pathological mixed-nesting cases (e.g. *italic wrapping **bold***) are not
37
+ * matched; the common cases — bold-containing-italic, adjacent emphasis, links
38
+ * with emphasised labels — all work.
39
+ */
40
+ import { type TemplateResult } from 'lit';
41
+ export type MarkdownNode = TemplateResult | string;
42
+ /** What a ``[label](url)`` becomes: a new-tab link, or a same-tab one the host routes. */
43
+ export type LinkTarget = {
44
+ kind: 'external';
45
+ href: string;
46
+ } | {
47
+ kind: 'internal';
48
+ href: string;
49
+ onActivate: (event: MouseEvent) => void;
50
+ };
51
+ export interface LinkPolicy {
52
+ /** The link for ``url``, or ``null`` to leave the markdown literal. */
53
+ link(url: string): LinkTarget | null;
54
+ /** Whether bare URLs and e-mail addresses are turned into links (linkify). */
55
+ autolink: boolean;
56
+ }
57
+ export declare const GUIDE_LINK_POLICY: LinkPolicy;
58
+ export declare function renderInlineMarkdown(src: string, policy?: LinkPolicy): MarkdownNode[];
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Product-derived names, the TypeScript twin of ``src/steppy/naming.py``.
3
+ *
4
+ * One literal per line on purpose: ``tests/test_tour_contract_sync.py`` reads
5
+ * this file with regular expressions and fails when a value drifts from the
6
+ * Python side. A future rename edits both files.
7
+ */
8
+ export declare const PRODUCT = "steppy";
9
+ export declare const TOUR_HOST_TAG = "steppy-tour-host";
10
+ export declare const TOURS_MANIFEST_KIND = "steppy-tours-manifest";
11
+ export declare const TOUR_FILE_KIND = "steppy-tour";
12
+ export declare const TOURS_MANIFEST_FILENAME = "tours.manifest.json";
13
+ export declare const TOURS_KILL_SWITCH_GLOBAL = "__STEPPY_TOURS_DISABLED__";
14
+ export declare const TOUR_RESUME_STORAGE_KEY = "steppy:tour";
15
+ /** ``globalThis[Symbol.for(...)]`` marks the host instance that owns the running tour. */
16
+ export declare const TOUR_ACTIVE_SYMBOL_KEY = "steppy.tour.active";
17
+ /** Prefix of every public CSS custom property (``--steppy-accent`` ...). */
18
+ export declare const CSS_TOKEN_PREFIX = "--steppy-";
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Bubble placement next to a highlighted rect, shared by the guide player's
3
+ * tooltip and the in-app tour popover. Pure math, no DOM.
4
+ *
5
+ * Called without options, ``placeTooltip`` is the guide's historical rule,
6
+ * byte for byte (guard: ``test/ui/placement.test.ts`` against a frozen copy).
7
+ * With options it honours a preferred side, keeps a margin from the stage
8
+ * edges, steers clear of rects to ``avoid`` and reports whether the bubble
9
+ * could not avoid covering the hotspot.
10
+ *
11
+ * ``Rect`` is declared here rather than imported from ``cursor/`` so the tour's
12
+ * type declarations do not pull the cursor animator in.
13
+ */
14
+ export interface Rect {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ }
20
+ export type TooltipSide = 'top' | 'bottom' | 'left' | 'right';
21
+ export interface TooltipPlacement {
22
+ side: TooltipSide;
23
+ /** Top-left offset, in display space, of the tooltip's bounding box. */
24
+ x: number;
25
+ y: number;
26
+ /** Only with options: true when no side fits and the bubble covers the hotspot. */
27
+ overlaps?: boolean;
28
+ }
29
+ export interface PlaceOptions {
30
+ /** Side to try first; ``auto`` (the default) uses the historical bias. */
31
+ preferred?: TooltipSide | 'auto';
32
+ /** Distance kept from every stage edge (default 0). */
33
+ margin?: number;
34
+ /** Rects a fitting side should not cover (e.g. the next step's target). */
35
+ avoid?: readonly Rect[];
36
+ }
37
+ type Size = {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ /**
42
+ * Decide which side of the hotspot the tooltip should sit on. Picks the side
43
+ * with the most room, then biases toward ``bottom`` for ties (matches
44
+ * Guideflow's default).
45
+ *
46
+ * All inputs and outputs are in display space (the same coordinate frame as
47
+ * the hotspot rect).
48
+ */
49
+ export declare function placeTooltip(hotspot: Rect, tooltip: Size, stage: Size, gap?: number, opts?: PlaceOptions): TooltipPlacement;
50
+ /** True when ``a`` and ``b`` share a positive area. */
51
+ export declare function intersects(a: Rect, b: Rect): boolean;
52
+ /** The overlap of ``a`` and ``b``, or ``null`` when they share no area. */
53
+ export declare function intersect(a: Rect, b: Rect): Rect | null;
54
+ /** The smallest rect containing both. */
55
+ export declare function union(a: Rect, b: Rect): Rect;
56
+ /** ``r`` grown by ``pad`` on every side. */
57
+ export declare function inflate(r: Rect, pad: number): Rect;
58
+ export declare function containsPoint(r: Rect, x: number, y: number): boolean;
59
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The string mechanism both players share: placeholder formatting, locale
3
+ * lookup with a base-language rung, and the chrome vocabulary they have in
4
+ * common (so "Next" reads the same in the guide and in the tour).
5
+ */
6
+ /** Replace ``{name}`` placeholders; unknown names stay as written. */
7
+ export declare function format(template: string, vars: Record<string, string | number>): string;
8
+ /**
9
+ * Bare language subtag, lowercased (``fr-BE`` -> ``fr``). Mirrors Python's
10
+ * ``steppy.locales.base_language``: lenient, never validates.
11
+ */
12
+ export declare function baseLanguage(tag: string): string;
13
+ /**
14
+ * The key of ``keys`` to use for ``requested``: an exact match (case- and
15
+ * ``_``/``-``-insensitive) first, then the requested tag's base language. The
16
+ * query is only ever truncated, never widened — ``fr`` does not match ``fr-BE``.
17
+ */
18
+ export declare function lookupLocale(keys: Iterable<string>, requested: string | null | undefined): string | null;
19
+ /**
20
+ * Bundled ``defaults`` for ``locale`` (else ``fallback``), with the host's
21
+ * sparse per-locale ``overrides`` merged on top. Without an override the
22
+ * bundled object itself is returned.
23
+ */
24
+ export declare function resolveStrings<T extends object>(defaults: Record<string, T>, locale: string, overrides?: Partial<Record<string, Partial<T>>>, fallback?: string): T;
25
+ export interface ChromeStrings {
26
+ next: string;
27
+ /** Placeholders: ``{current}`` and ``{total}``. */
28
+ progress: string;
29
+ }
30
+ /** Chrome words the guide and the tour share, per bundled locale. */
31
+ export declare const CHROME_STRINGS: Record<'en' | 'fr' | 'nl' | 'de', ChromeStrings>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Default look values shared by the guide player and the in-app tour overlay.
3
+ *
4
+ * Constants only, never data: they are interpolated into the ``css`` tagged
5
+ * templates with ``cssValue`` (Lit's ``unsafeCSS``), which concatenates the
6
+ * value verbatim — ``baseStyles.cssText`` is byte-identical to the literal
7
+ * stylesheet it replaced (guard: ``test/ui/guide-styles-stable.test.ts``).
8
+ */
9
+ import { type CSSResult } from 'lit';
10
+ /** The guide's palette (``--steppy-*`` defaults in ``templates/base-styles.ts``). */
11
+ export declare const PALETTE: {
12
+ readonly bg: "#f4f1ea";
13
+ readonly surface: "#fbf9f4";
14
+ readonly chromeBg: "#efece3";
15
+ readonly fg: "#1f1d1a";
16
+ readonly muted: "#8a857c";
17
+ readonly border: "#e1ddd1";
18
+ readonly accent: "#d24f2c";
19
+ readonly accentWeak: "rgba(210, 79, 44, 0.35)";
20
+ readonly success: "#3a7d44";
21
+ };
22
+ /** System font stacks only: offline, no CDN. */
23
+ export declare const FONTS: {
24
+ readonly serif: "ui-serif, Georgia, 'Times New Roman', serif";
25
+ readonly sans: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif";
26
+ readonly mono: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
27
+ };
28
+ /** The dark bubble both players draw next to a target (guide tooltip, tour popover). */
29
+ export declare const BUBBLE_LOOK: {
30
+ readonly padding: "8px 12px";
31
+ readonly radius: "6px";
32
+ readonly maxWidth: "280px";
33
+ readonly fontSize: "14px";
34
+ readonly lineHeight: "1.4";
35
+ readonly shadow: "0 4px 12px rgba(0, 0, 0, 0.2)";
36
+ };
37
+ export declare const BUTTON_LOOK: {
38
+ readonly radius: "4px";
39
+ readonly padding: "4px 10px";
40
+ };
41
+ /**
42
+ * Tour overlay defaults. The accent differs from the guide's on purpose:
43
+ * ``#d24f2c`` measures 4.29:1 against white text, below WCAG AA for the
44
+ * overlay's buttons; ``#a8410e`` measures 6.13:1 (guard: ``test/tour/small-modules.test.ts``).
45
+ */
46
+ export declare const TOUR_DEFAULTS: {
47
+ readonly bubbleBg: "#1f1d1a";
48
+ readonly bubbleFg: "#fbf9f4";
49
+ readonly muted: "#c9c5bd";
50
+ readonly accent: "#a8410e";
51
+ readonly accentFg: "#ffffff";
52
+ readonly focus: "#f09a6a";
53
+ readonly scrim: "rgba(31, 29, 26, 0.45)";
54
+ readonly radius: "6px";
55
+ };
56
+ /** A token value inside a ``css`` template (inserted verbatim, never data). */
57
+ export declare const cssValue: (value: string | number) => CSSResult;
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
2
  "name": "@steppy/player",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.0",
4
+ "description": "Steppy players — the interactive guide (Lit web component + manifest validator) and the in-app tour overlay",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Steppy-dev/steppy.git",
9
+ "directory": "packages/player"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/steppy-player.js",
13
+ "module": "./dist/steppy-player.js",
14
+ "types": "./dist/types/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/types/index.d.ts",
18
+ "default": "./dist/steppy-player.js"
19
+ },
20
+ "./schema.json": "./schema/guide.schema.json",
21
+ "./tour": {
22
+ "types": "./dist/types/tour/index.d.ts",
23
+ "default": "./dist/steppy-tour.js"
24
+ }
25
+ },
26
+ "typesVersions": {
27
+ "*": {
28
+ "tour": [
29
+ "./dist/types/tour/index.d.ts"
30
+ ]
31
+ }
32
+ },
33
+ "sideEffects": true,
34
+ "files": [
35
+ "dist",
36
+ "schema",
37
+ "LICENSE",
38
+ "NOTICE",
39
+ "THIRD_PARTY_LICENSES.txt"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "scripts": {
45
+ "build": "vite build && vite build -c vite.iife.config.ts && vite build -c vite.video.config.ts && npm run build:tour && npm run build:schema",
46
+ "build:esm": "vite build",
47
+ "build:iife": "vite build -c vite.iife.config.ts",
48
+ "build:video": "vite build -c vite.video.config.ts",
49
+ "build:tour": "vite build -c vite.tour.config.ts && npm run build:types",
50
+ "build:schema": "tsx scripts/emit-json-schema.ts",
51
+ "size:tour": "tsx scripts/check-tour-size.ts",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "typecheck": "tsc --noEmit",
55
+ "build:types": "tsc -p tsconfig.types.json",
56
+ "check:pack": "tsx scripts/check-pack.ts",
57
+ "prepack": "npm run build"
58
+ },
59
+ "dependencies": {
60
+ "lit": "^3.2.0",
61
+ "zod": "^3.23.0"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^20.14.0",
65
+ "happy-dom": "^15.7.0",
66
+ "tsx": "^4.19.0",
67
+ "typescript": "^5.6.0",
68
+ "vite": "^5.4.0",
69
+ "vitest": "^2.1.0",
70
+ "zod-to-json-schema": "^3.23.0"
71
+ }
72
+ }
@@ -0,0 +1,19 @@
1
+ # Generated JSON Schema
2
+
3
+ `guide.schema.json` here is generated from the Zod schema at
4
+ [../src/manifest/schema.ts](../src/manifest/schema.ts).
5
+
6
+ Regenerate with:
7
+
8
+ ```
9
+ npm run build:schema
10
+ ```
11
+
12
+ The Zod schema is the source of truth. The JSON Schema is shipped for external
13
+ tooling (IDE completion, validation in downstream projects, docs). The runtime
14
+ validator in `parseManifest()` uses the Zod schema directly.
15
+
16
+ Cross-field rules (e.g. `defaultLocale` must appear in `locales`) live in a
17
+ `superRefine` block on the Zod schema and are **not** emitted into the JSON
18
+ Schema — JSON Schema lacks the expressiveness for them. Treat JSON Schema as
19
+ structural validation; `parseManifest()` is the authority.