@glowhop/core-tour 1.0.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @glowhop/core-tour
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - e6da5bf: GlowTour.js V.1.0.0 release
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Glowhop
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @glowhop/core-tour
2
+
3
+ ESM-only, framework-agnostic workflow controller and DOM driver. Core owns workflow state, navigation, target resolution, and DOM-level tour behavior; adapters provide component rendering and composition. Connecting a root succeeds without a popover; running a non-empty workflow fails if the root or popover is missing. The adapter-author entry point is [`@glowhop/core-tour/adapter`](https://github.com/Glowhop/GlowTour.js/blob/main/packages/core/src/adapter.ts).
4
+
5
+ Compatibility: framework-independent ESM package. Core provides no SSR-rendered UI; hydration is not applicable to Core itself.
6
+
7
+ <!-- glow-tour:snippet core-workflow -->
8
+ ```ts
9
+ import { createGlowTour } from "@glowhop/core-tour";
10
+
11
+ const tour = createGlowTour();
12
+ const workflow = tour.create("intro").step({ id: "welcome", target: "#welcome", title: "Welcome", content: "Hello." }).build();
13
+ // Pass tour to a mounted adapter/default composition, then call:
14
+ // await tour.run(workflow);
15
+ ```
16
+
17
+ ## Builder and controller
18
+
19
+ `createGlowTour<T>(options?: GlowTourOptions)` returns a controller. `tour.create(name, options)` returns a builder; call `.step(...)`, then `.build()` to obtain an immutable workflow. Targets may be a selector, an `HTMLElement`, or a resolver `(context) => HTMLElement | null | Promise<HTMLElement | null>`.
20
+
21
+ | Capability | API | Notes |
22
+ | --- | --- | --- |
23
+ | Placement | `popover.placementTryOrder`, `indicator.placementTryOrder` | Try `top`, `bottom`, `left`, `right`; the resolved position may be `center`. |
24
+ | Interaction | `behavior.allowInteraction` | Allows pointer interaction through the overlay. |
25
+ | Scroll | step/start `scroll` | Uses `behavior`, `block`, and `inline` scroll options. |
26
+ | Callbacks | `onStart`, `onCancel`, `onFinish`; `beforeAdvance`, `beforePrevious`, `beforeCancel` | Start callbacks are workflow options; transition callbacks are step builder methods. |
27
+ | Actions | `.do(fn)`, `.wait(ms)`, `.waitUntil(fn)`, `.waitUntilElement(selector)` | `waitUntil` defaults to a 16 ms interval and 3000 ms timeout. |
28
+ | Target events | `.onTargetEvent("click", fn)` | Handlers receive the event and step context. |
29
+
30
+ `tour.state.get()` returns status, current step, navigation capabilities, and errors; `tour.state.subscribe(listener)` observes changes. The controller exposes `run`, `advance`, `previous`, `goToStep`, and `cancel`. A new run or navigation cancels the previous operation; `dispose()` cancels pending work, releases the root, and makes the controller unusable.
31
+
32
+ ## Errors and rendering fallbacks
33
+
34
+ Pass `onSubscriberError(error)` in `GlowTourOptions` to observe failures from state and step-props subscribers:
35
+
36
+ ```ts
37
+ import { createGlowTour } from "@glowhop/core-tour";
38
+
39
+ const tour = createGlowTour({
40
+ onSubscriberError(error) {
41
+ console.error("Tour subscriber failed", error);
42
+ },
43
+ });
44
+ ```
45
+
46
+ Subscriber failures are isolated and normalized to `Error`; they do not fail the tour transition. If `onSubscriberError` throws or returns a rejected promise, that failure is reported asynchronously outside the transition.
47
+
48
+ Web Animations are optional. When the capability is missing or unsupported, Core applies the final DOM state immediately and continues without animation.
49
+
50
+ A failure from a mounted rendering layer is fatal: the command rejects, and the next published state has `status === "error"` with the failure in `state.error`. Core does not publish `active` for the failed step.
package/adapter.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { type CssStyleRecord, OVERLAY_IDLE_ATTRIBUTES, OVERLAY_IDLE_STYLE, OVERLAY_PATH_IDLE_ATTRIBUTES, POINTER_IDLE_ATTRIBUTES, POINTER_IDLE_STYLE, POPOVER_IDLE_ATTRIBUTES, POPOVER_IDLE_STYLE, styleRecordToCamelCase, styleRecordToCssText } from "./elements/idle-presentation";
2
+ import { type AdapterRootBinding, type AdapterRootIds } from "./runtime/adapter-contract";
3
+ import type { GlowTour } from "./types";
4
+ export type { AdapterRootBinding, AdapterRootIds, CssStyleRecord };
5
+ /**
6
+ * The idle (pre-bind / server-rendered) presentation for tour elements.
7
+ *
8
+ * Framework adapters render these directly into their markup so the popover,
9
+ * pointer and overlay are out of flow and invisible before a tour's runtime
10
+ * ever touches the DOM — on the server, and in the window between hydration
11
+ * and an adapter binding its elements. `initializeProps()` on the
12
+ * corresponding core element classes applies the same constants
13
+ * imperatively, so rendered markup and runtime application can never drift.
14
+ *
15
+ * Excludes the overlay's `viewBox`, which depends on the live viewport and
16
+ * can only be computed once the element exists in a real DOM.
17
+ */
18
+ export { OVERLAY_IDLE_ATTRIBUTES, OVERLAY_IDLE_STYLE, OVERLAY_PATH_IDLE_ATTRIBUTES, POINTER_IDLE_ATTRIBUTES, POINTER_IDLE_STYLE, POPOVER_IDLE_ATTRIBUTES, POPOVER_IDLE_STYLE, styleRecordToCamelCase, styleRecordToCssText, };
19
+ /**
20
+ * Connects a GlowTour.js instance to a DOM root element.
21
+ *
22
+ * Framework adapters call this to initialize tour UI bindings. It must be called
23
+ * with a valid GlowTour instance created via createGlowTour.
24
+ *
25
+ * @param tour The GlowTour instance.
26
+ * @param options Configuration for the adapter root binding.
27
+ * @param options.root The DOM element where tour UI will be rendered.
28
+ * @param options.idPrefix Optional prefix for internal element IDs.
29
+ * @returns The adapter root binding for managing the tour UI.
30
+ * @throws Throws if the tour is not a valid GlowTour instance.
31
+ */
32
+ export declare function connectGlowTourRoot<T>(tour: GlowTour<T>, options: {
33
+ readonly idPrefix?: string;
34
+ readonly root: HTMLElement;
35
+ }): AdapterRootBinding;
package/adapter.js ADDED
@@ -0,0 +1,84 @@
1
+ // packages/core/src/elements/idle-presentation.ts
2
+ var OVERLAY_IDLE_STYLE = {
3
+ "clip-rule": "evenodd",
4
+ "fill-rule": "evenodd",
5
+ height: "100%",
6
+ left: "0px",
7
+ "pointer-events": "none",
8
+ position: "fixed",
9
+ "stroke-linejoin": "round",
10
+ "stroke-miterlimit": "2",
11
+ top: "0px",
12
+ width: "100%",
13
+ "z-index": "10000"
14
+ };
15
+ var OVERLAY_IDLE_ATTRIBUTES = {
16
+ "aria-hidden": "true",
17
+ "data-glow-tour-allow-interaction": "false",
18
+ inert: "true"
19
+ };
20
+ var OVERLAY_PATH_IDLE_ATTRIBUTES = {
21
+ cursor: "auto",
22
+ opacity: "0",
23
+ "pointer-events": "auto"
24
+ };
25
+ var POINTER_IDLE_STYLE = {
26
+ left: "0px",
27
+ opacity: "0",
28
+ "pointer-events": "none",
29
+ position: "fixed",
30
+ top: "0px",
31
+ "will-change": "top, left, transform, opacity",
32
+ "z-index": "10002"
33
+ };
34
+ var POINTER_IDLE_ATTRIBUTES = {
35
+ "aria-hidden": "true"
36
+ };
37
+ var POPOVER_IDLE_STYLE = {
38
+ left: "0px",
39
+ opacity: "0",
40
+ position: "fixed",
41
+ top: "0px",
42
+ "transform-origin": "center center",
43
+ "z-index": "10001"
44
+ };
45
+ var POPOVER_IDLE_ATTRIBUTES = {
46
+ "aria-hidden": "true",
47
+ inert: "true",
48
+ tabindex: "-1"
49
+ };
50
+ function styleRecordToCssText(style) {
51
+ return Object.entries(style).map(([property, value]) => `${property}: ${value};`).join(" ");
52
+ }
53
+ function styleRecordToCamelCase(style) {
54
+ const result = {};
55
+ for (const [property, value] of Object.entries(style)) {
56
+ result[property.replace(/-([a-z0-9])/g, (_match, char) => char.toUpperCase())] = value;
57
+ }
58
+ return result;
59
+ }
60
+
61
+ // packages/core/src/runtime/adapter-contract.ts
62
+ var ADAPTER_BRIDGE_SYMBOL = Symbol.for("@glowhop/core-tour/adapter-bridge/v1");
63
+ var ADAPTER_BRIDGE_VERSION = 1;
64
+
65
+ // packages/core/src/adapter.ts
66
+ function connectGlowTourRoot(tour, options) {
67
+ const bridge = Reflect.get(tour, ADAPTER_BRIDGE_SYMBOL);
68
+ if (typeof bridge !== "object" || bridge === null || Reflect.get(bridge, "version") !== ADAPTER_BRIDGE_VERSION || typeof Reflect.get(bridge, "connectRoot") !== "function") {
69
+ throw new Error("Incompatible GlowTour.js adapter bridge");
70
+ }
71
+ return bridge.connectRoot(options);
72
+ }
73
+ export {
74
+ styleRecordToCssText,
75
+ styleRecordToCamelCase,
76
+ connectGlowTourRoot,
77
+ POPOVER_IDLE_STYLE,
78
+ POPOVER_IDLE_ATTRIBUTES,
79
+ POINTER_IDLE_STYLE,
80
+ POINTER_IDLE_ATTRIBUTES,
81
+ OVERLAY_PATH_IDLE_ATTRIBUTES,
82
+ OVERLAY_IDLE_STYLE,
83
+ OVERLAY_IDLE_ATTRIBUTES
84
+ };
@@ -0,0 +1,148 @@
1
+ import { type WorkflowDefinition, type WorkflowStepDraft } from "../definition";
2
+ import type { EventHandler, StartOptions, StepAction, StepContext, StepParameters, StepTransitionAction, WaitUntilOptions } from "../types";
3
+ declare const STEP_BUILDER_INTERNAL: unique symbol;
4
+ /** Standard DOM event names supported by HTML elements. */
5
+ export type EventName = keyof HTMLElementEventMap;
6
+ type EventForName<TEventName extends EventName> = HTMLElementEventMap[TEventName];
7
+ /** Predicate polled by `.waitUntil()` until it returns `true` or the wait times out. */
8
+ type WaitUntilPredicate<T> = (context: StepContext<T>) => Promise<boolean> | boolean;
9
+ /** Builder for constructing a tour workflow step-by-step. */
10
+ export declare class WorkflowBuilder<T> {
11
+ readonly name: string;
12
+ private readonly options;
13
+ private readonly steps;
14
+ private currentStep;
15
+ private definition;
16
+ /**
17
+ * Creates a new workflow builder.
18
+ * @param name The name of the workflow.
19
+ * @param options Tour start options (lifecycle hooks, display options, behavior).
20
+ */
21
+ constructor(name: string, options?: StartOptions<T>);
22
+ /**
23
+ * Add a new step to the workflow.
24
+ * @param options Step configuration.
25
+ * @returns A WorkflowStepBuilder for chaining additional configuration.
26
+ */
27
+ step(options: StepParameters<T>): WorkflowStepBuilder<T>;
28
+ /**
29
+ * Append another workflow's steps to this workflow.
30
+ * @param workflow The workflow to append.
31
+ * @returns A WorkflowStepBuilder for the last appended step.
32
+ */
33
+ append(workflow: WorkflowDefinition<T>): WorkflowStepBuilder<T>;
34
+ /**
35
+ * Build and return the workflow definition. Can be called multiple times.
36
+ * @returns A frozen workflow definition ready to run.
37
+ */
38
+ build(): WorkflowDefinition<T>;
39
+ private assertBuilding;
40
+ private commitCurrentStep;
41
+ }
42
+ /** Builder for configuring a single tour step with actions and event handlers. */
43
+ export declare class WorkflowStepBuilder<T> {
44
+ private readonly owner;
45
+ private readonly draft;
46
+ private active;
47
+ /**
48
+ * Creates a step builder for the given workflow.
49
+ * @param owner The parent WorkflowBuilder.
50
+ * @param draft The step definition being built.
51
+ */
52
+ constructor(owner: WorkflowBuilder<T>, draft: WorkflowStepDraft<T>);
53
+ /**
54
+ * Add another step to the workflow after this one.
55
+ * @param options The new step configuration.
56
+ * @returns The new WorkflowStepBuilder.
57
+ */
58
+ step(options: StepParameters<T>): WorkflowStepBuilder<T>;
59
+ /**
60
+ * Append another workflow's steps after this step.
61
+ * @param workflow The workflow to append.
62
+ * @returns The WorkflowStepBuilder for the last appended step.
63
+ */
64
+ append(workflow: WorkflowDefinition<T>): WorkflowStepBuilder<T>;
65
+ /**
66
+ * Build and return the workflow definition.
67
+ * @returns A frozen workflow definition ready to run.
68
+ */
69
+ build(): WorkflowDefinition<T>;
70
+ /**
71
+ * Add an action that clicks the target element when the step is entered.
72
+ * @returns This builder for chaining.
73
+ */
74
+ clickTarget(): this;
75
+ /**
76
+ * Add an action that focuses the target element when the step is entered.
77
+ * @returns This builder for chaining.
78
+ */
79
+ focusTarget(): this;
80
+ /**
81
+ * Add a delay action.
82
+ * @param timeMs The delay duration in milliseconds.
83
+ * @returns This builder for chaining.
84
+ */
85
+ wait(timeMs: number): this;
86
+ /**
87
+ * Add an action that waits for a condition before continuing.
88
+ * @param predicate Function that returns true when the condition is met.
89
+ * @param options Timeout and polling interval options.
90
+ * @returns This builder for chaining.
91
+ */
92
+ waitUntil(predicate: WaitUntilPredicate<T>, options?: WaitUntilOptions): this;
93
+ /**
94
+ * Add an action that waits for an element to appear in the DOM.
95
+ * @param selector CSS selector for the element to wait for.
96
+ * @param options Timeout and polling interval options.
97
+ * @returns This builder for chaining.
98
+ */
99
+ waitUntilElement(selector: string, options?: WaitUntilOptions): this;
100
+ /**
101
+ * Add a custom action callback to run when the step is entered.
102
+ * @param callback The action callback.
103
+ * @returns This builder for chaining.
104
+ */
105
+ do(callback: StepAction<T>): this;
106
+ /**
107
+ * Add a callback that runs before advancing to the next step.
108
+ * @param callback The transition callback.
109
+ * @returns This builder for chaining.
110
+ */
111
+ beforeAdvance(callback: StepTransitionAction<T>): this;
112
+ /**
113
+ * Add a callback that runs before going to the previous step.
114
+ * @param callback The transition callback.
115
+ * @returns This builder for chaining.
116
+ */
117
+ beforePrevious(callback: StepTransitionAction<T>): this;
118
+ /**
119
+ * Add a callback that runs before cancelling the tour.
120
+ * @param callback The transition callback.
121
+ * @returns This builder for chaining.
122
+ */
123
+ beforeCancel(callback: StepTransitionAction<T>): this;
124
+ /**
125
+ * Add an event listener to the target element for a specific event name.
126
+ * @param event The event name.
127
+ * @param callback The handler function.
128
+ * @returns This builder for chaining.
129
+ */
130
+ onTargetEvent<const TEventName extends EventName>(event: TEventName, callback: EventHandler<T, EventForName<TEventName>>["callback"]): this;
131
+ /**
132
+ * Add an event listener to the target element for multiple event names.
133
+ * @param events Array of event names.
134
+ * @param callback The handler function.
135
+ * @returns This builder for chaining.
136
+ */
137
+ onTargetEvent<const TEventNames extends readonly EventName[]>(events: TEventNames, callback: EventHandler<T, EventForName<TEventNames[number]>>["callback"]): this;
138
+ /**
139
+ * Add an event listener to the target element for a custom event.
140
+ * @param event The event name.
141
+ * @param callback The handler function.
142
+ * @returns This builder for chaining.
143
+ */
144
+ onTargetEvent<TEvent extends Event>(event: string, callback: EventHandler<T, TEvent>["callback"]): this;
145
+ [STEP_BUILDER_INTERNAL](): WorkflowStepDraft<T>;
146
+ private assertActive;
147
+ }
148
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { WorkflowDefinitionFromConfig } from "./types";
2
+ import { type ValidateWorkflowConfigOptions } from "./validate";
3
+ /** Options accepted by `createWorkflowFromConfig`. */
4
+ export type CreateWorkflowFromConfigOptions = ValidateWorkflowConfigOptions;
5
+ /**
6
+ * Builds a `WorkflowDefinition<T>` from a JSON-serializable `WorkflowConfig<T>`. Defaults to
7
+ * `T = string`, the untrusted-JSON case; instantiate with a framework content type (e.g.
8
+ * `createWorkflowFromConfig<ReactNode>(...)`) for a same-runtime config carrying rich content.
9
+ *
10
+ * Validates the whole config first (structure, strict unknown-key rejection, and slot-appropriate
11
+ * action shapes), collecting all issues into a single `ConfigValidationError` rather than failing
12
+ * on the first one, then drives the existing `WorkflowBuilder<T>` to produce the definition.
13
+ *
14
+ * By default `title`/`content` must be plain strings, regardless of `T`, since the runtime cannot
15
+ * otherwise know what `T` is. Pass `options.validateContent` to accept a richer `T`.
16
+ *
17
+ * The returned definition carries the original (frozen) config as `.source`, so a future JSON
18
+ * exporter can round-trip without re-deriving the config from the built definition.
19
+ *
20
+ * @param config The parsed JSON (or equivalent plain object) to build from. Accepts `unknown` so
21
+ * callers can pass `JSON.parse(...)` output directly; it is validated and narrowed internally.
22
+ * @param options Options; see {@link CreateWorkflowFromConfigOptions}.
23
+ * @throws {ConfigValidationError} When the config is invalid.
24
+ * @returns A frozen `WorkflowDefinition<T>` with `.source` attached.
25
+ */
26
+ export declare function createWorkflowFromConfig<T = string>(config: unknown, options?: CreateWorkflowFromConfigOptions): WorkflowDefinitionFromConfig<T>;
@@ -0,0 +1,6 @@
1
+ export type { CreateWorkflowFromConfigOptions } from "./from-config";
2
+ export { createWorkflowFromConfig } from "./from-config";
3
+ export type { BuiltinAction, ConfigValidationIssue, EventHandlerConfig, LifecycleActionRef, StepActionRef, StepConfig, TransitionActionRef, WorkflowConfig, WorkflowDefinitionFromConfig, } from "./types";
4
+ export { ConfigValidationError } from "./types";
5
+ export type { ValidateWorkflowConfigOptions } from "./validate";
6
+ export { validateWorkflowConfig } from "./validate";