@sunboard/react 0.1.0 → 0.1.2
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/dist/index.d.mts +10 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { RuntimeBootstrapRequest, RuntimeBootstrapResponse, RuntimeExperience, RuntimeProgress, RuntimeTrackRequest, RuntimeTrackResponse, SunboardRuntimeApiError, SunboardRuntimeClient, SunboardRuntimeClientOptions } from "@sunboard/core/runtime-api";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
4
4
|
import { NormalizedSunboardSpec, SunboardHotspot, SunboardStep, SunboardTourStep, TrackEventName } from "@sunboard/core";
|
|
5
5
|
|
|
6
6
|
//#region src/adapters/navigation.d.ts
|
|
@@ -74,6 +74,11 @@ type SunboardProviderProps = {
|
|
|
74
74
|
mode?: SunboardRuntimeMode;
|
|
75
75
|
route?: string;
|
|
76
76
|
navigate?: NavigateCallback;
|
|
77
|
+
/**
|
|
78
|
+
* Override the runtime API host. Dev-only — leave unset in production so the
|
|
79
|
+
* SDK targets the hosted Sunboard runtime API. Defaults to
|
|
80
|
+
* `DEFAULT_RUNTIME_API_URL`.
|
|
81
|
+
*/
|
|
77
82
|
apiUrl?: string;
|
|
78
83
|
publishableKey?: string;
|
|
79
84
|
environment?: string;
|
|
@@ -92,16 +97,16 @@ declare function SunboardProvider({
|
|
|
92
97
|
environment,
|
|
93
98
|
onTrack,
|
|
94
99
|
children
|
|
95
|
-
}: SunboardProviderProps):
|
|
100
|
+
}: SunboardProviderProps): react_jsx_runtime2.JSX.Element;
|
|
96
101
|
//#endregion
|
|
97
102
|
//#region src/components/SunboardHotspots.d.ts
|
|
98
|
-
declare function SunboardHotspots():
|
|
103
|
+
declare function SunboardHotspots(): react_jsx_runtime2.JSX.Element;
|
|
99
104
|
//#endregion
|
|
100
105
|
//#region src/components/SunboardTour.d.ts
|
|
101
|
-
declare function SunboardTour():
|
|
106
|
+
declare function SunboardTour(): react_jsx_runtime2.JSX.Element | null;
|
|
102
107
|
//#endregion
|
|
103
108
|
//#region src/components/Sunboard.d.ts
|
|
104
|
-
declare function SunboardChecklist():
|
|
109
|
+
declare function SunboardChecklist(): react_jsx_runtime2.JSX.Element | null;
|
|
105
110
|
declare const Sunboard: typeof SunboardChecklist & {
|
|
106
111
|
Checklist: typeof SunboardChecklist;
|
|
107
112
|
Hotspots: typeof SunboardHotspots;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapters/navigation.ts","../src/hooks/sunboard-context.ts","../src/components/SunboardProvider.tsx","../src/components/SunboardHotspots.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx","../src/hooks/useSunboardPreviewSpec.ts","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts"],"sourcesContent":[],"mappings":";;;;;;KAAY,gBAAA,2BAA2C;;;KCS3C,YAAA;;;;eAIG;ADbf,CAAA;KCgBY,eAAA,GAAkB;KAElB,WAAA;;AATZ,CAAA,GAAY;EAOA,EAAA,EAAA,KAAA;EAEA,MAAA,EAAA,WAAW,GAAA,cAAA,GAAA,eAAA;AAIvB,CAAA;AAIY,KAJA,UAAA,GAIA;EAEA,EAAA,EAAA,IAAA;AAQZ,CAAA,GAAY;EAQA,EAAA,EAAA,KAAA;EACH,MAAA,EAAA,WAAA,GAAA,cAAA,GAAA,cAAA;CACA;AAGD,KAvBI,mBAAA,GAuBJ,YAAA,GAAA,SAAA;AACa,KAtBT,iBAAA,GAsBS;EACA,OAAA,EAAA,MAAA;EAGP,KAAA,CAAA,EAAA,MAAA;EACD,OAAA,CAAA,EAAA,MAAA;EAEE,MAAA,CAAA,EAAA,MAAA;EACE,OAAA,EAAA,MAAA;CACF;AAAR,KAvBK,kBAAA,GAuBL;EACmC,GAAA,EAAA,MAAA;EAAR,IAAA,EAAA,MAAA;EACL,IAAA,EAtBrB,gBAsBqB;EAAR,SAAA,EAAA,MAAA;EACQ,UAAA,EAAA,MAAA;CAAR;AACI,KAnBb,oBAAA,GAmBa;EAAiB,IAAA,CAAA,EAlBjC,sBAkBiC,GAAA,IAAA;EACb,IAAA,CAAA,EAlBpB,YAkBoB,GAAA,IAAA;EAAyB,OAAA,EAAA,OAAA;EAAR,KAAA,CAAA,EAAA,MAAA;EACnB,IAAA,EAhBnB,mBAgBmB;EACsB,iBAAA,EAhB5B,WAgB4B,CAAA,MAAA,CAAA;EAA9B,iBAAA,EAfE,WAeF,CAAA,MAAA,CAAA;EAAK,cAAA,EAAA,MAAA;;cAZV;aACD;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapters/navigation.ts","../src/hooks/sunboard-context.ts","../src/components/SunboardProvider.tsx","../src/components/SunboardHotspots.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx","../src/hooks/useSunboardPreviewSpec.ts","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { SunboardRuntimeApiError, SunboardRuntimeClient, SunboardRuntimeClient as SunboardRuntimeClient$1, routeMatches } from "@sunboard/core/runtime-api";
|
|
4
|
+
import { DEFAULT_RUNTIME_API_URL, SunboardRuntimeApiError, SunboardRuntimeClient, SunboardRuntimeClient as SunboardRuntimeClient$1, routeMatches } from "@sunboard/core/runtime-api";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { FloatingArrow, FloatingPortal, arrow, autoUpdate, flip, offset, shift, useFloating } from "@floating-ui/react";
|
|
7
7
|
|
|
@@ -156,9 +156,9 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, mode: mo
|
|
|
156
156
|
const currentOrigin = getBrowserOrigin();
|
|
157
157
|
const preview = useSunboardPreviewSpec();
|
|
158
158
|
const client = useMemo(() => {
|
|
159
|
-
if (!
|
|
159
|
+
if (!publishableKey) return null;
|
|
160
160
|
return new SunboardRuntimeClient$1({
|
|
161
|
-
apiUrl,
|
|
161
|
+
apiUrl: apiUrl || DEFAULT_RUNTIME_API_URL,
|
|
162
162
|
publishableKey,
|
|
163
163
|
sdkVersion: SDK_VERSION
|
|
164
164
|
});
|
|
@@ -223,11 +223,7 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, mode: mo
|
|
|
223
223
|
if (!resolvedSpec) return;
|
|
224
224
|
const tourCompletedStepKeys = resolvedSpec.checklist.steps.filter((step) => step.completeWhen?.tour && effectiveCompletedTourKeys.has(step.completeWhen.tour)).map((step) => step.key);
|
|
225
225
|
if (tourCompletedStepKeys.length === 0) return;
|
|
226
|
-
setCompletedStepKeys((current) =>
|
|
227
|
-
const next = new Set(current);
|
|
228
|
-
for (const stepKey of tourCompletedStepKeys) next.add(stepKey);
|
|
229
|
-
return next;
|
|
230
|
-
});
|
|
226
|
+
setCompletedStepKeys((current) => mergeKeys(current, tourCompletedStepKeys));
|
|
231
227
|
}, [effectiveCompletedTourKeys, resolvedSpec]);
|
|
232
228
|
const activeTour = useMemo(() => {
|
|
233
229
|
if (!resolvedSpec || !activeTourState) return null;
|
|
@@ -294,11 +290,7 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, mode: mo
|
|
|
294
290
|
reason: "missing-user"
|
|
295
291
|
};
|
|
296
292
|
const matchingStepKeys = resolvedSpec.checklist.steps.filter((step) => step.completeWhen?.event === eventName).map((step) => step.key);
|
|
297
|
-
if (matchingStepKeys.length > 0) setCompletedStepKeys((current) =>
|
|
298
|
-
const next = new Set(current);
|
|
299
|
-
for (const stepKey of matchingStepKeys) next.add(stepKey);
|
|
300
|
-
return next;
|
|
301
|
-
});
|
|
293
|
+
if (matchingStepKeys.length > 0) setCompletedStepKeys((current) => mergeKeys(current, matchingStepKeys));
|
|
302
294
|
let networkOk = true;
|
|
303
295
|
if (hostedMode && client && experienceKey) try {
|
|
304
296
|
applyProgress((await client.track({
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["eventSource: EventSource | null","SunboardRuntimeClient","resolvedMode: SunboardRuntimeMode","flat: FlatUser","current: unknown"],"sources":["../src/adapters/navigation.ts","../src/hooks/sunboard-context.ts","../src/hooks/useSunboardPreviewSpec.ts","../src/version.ts","../src/components/SunboardProvider.tsx","../src/lib/interpolate-tokens.ts","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts","../src/icons/index.tsx","../src/components/ChecklistStep.tsx","../src/hooks/useInterpolated.ts","../src/hooks/useTargetElement.ts","../src/components/SunboardHotspots.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx"],"sourcesContent":["export type NavigateCallback = (url: string) => void | Promise<void>;\n\nexport async function navigateWithFallback(\n url: string,\n navigate?: NavigateCallback\n): Promise<void> {\n if (navigate) {\n await navigate(url);\n return;\n }\n\n if (typeof window !== \"undefined\") {\n window.location.assign(url);\n }\n}\n","import { createContext } from \"react\";\nimport type {\n NormalizedSunboardSpec,\n SunboardHotspot,\n SunboardStep,\n SunboardTourStep,\n TrackEventName\n} from \"@sunboard/core\";\n\nexport type SunboardUser = {\n id: string;\n email?: string | null;\n group?: string | null;\n properties?: Record<string, unknown>;\n};\n\nexport type TrackProperties = Record<string, unknown>;\n\nexport type TrackResult =\n | { ok: true }\n | { ok: false; reason: \"not-ready\" | \"missing-user\" | \"network-error\" };\n\nexport type TourResult =\n | { ok: true }\n | { ok: false; reason: \"not-ready\" | \"missing-user\" | \"missing-tour\" };\n\nexport type SunboardRuntimeMode = \"production\" | \"preview\";\n\nexport type SunboardTourError = {\n message: string;\n route?: string;\n stepKey?: string;\n target?: string;\n tourKey: string;\n};\n\nexport type ActiveSunboardTour = {\n key: string;\n name: string;\n step: SunboardTourStep;\n stepIndex: number;\n totalSteps: number;\n};\n\nexport type SunboardContextValue = {\n spec?: NormalizedSunboardSpec | null;\n user?: SunboardUser | null;\n loading: boolean;\n route?: string;\n mode: SunboardRuntimeMode;\n completedStepKeys: ReadonlySet<string>;\n completedTourKeys: ReadonlySet<string>;\n completedCount: number;\n totalSteps: number;\n activeTour: ActiveSunboardTour | null;\n tourError: SunboardTourError | null;\n track: (\n eventName: TrackEventName,\n properties?: TrackProperties\n ) => Promise<TrackResult>;\n startTour: (tourKey: string) => Promise<TourResult>;\n dismissTour: () => Promise<TourResult>;\n advanceTour: () => Promise<TourResult>;\n navigateToStep: (step: SunboardStep) => Promise<void>;\n startChecklistStep: (step: SunboardStep) => Promise<TourResult | void>;\n reportTourError: (error: SunboardTourError | null) => void;\n visibleHotspots: Array<{ key: string; hotspot: SunboardHotspot }>;\n};\n\nexport const SunboardContext = createContext<SunboardContextValue | null>(null);\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { NormalizedSunboardSpec } from \"@sunboard/core\";\n\nexport type SunboardPreviewSpecState = {\n error: Error | null;\n loading: boolean;\n source: \"none\" | \"preview\";\n spec: NormalizedSunboardSpec | null;\n};\n\nexport function useSunboardPreviewSpec(): SunboardPreviewSpecState {\n const [state, setState] = useState<SunboardPreviewSpecState>(() => ({\n error: null,\n loading: getPreviewSpecUrl() !== null,\n source: \"none\",\n spec: null\n }));\n\n useEffect(() => {\n const previewUrl = getPreviewSpecUrl();\n\n if (!previewUrl) {\n setState({\n error: null,\n loading: false,\n source: \"none\",\n spec: null\n });\n return;\n }\n\n const controller = new AbortController();\n let cancelled = false;\n let eventSource: EventSource | null = null;\n\n const loadSpec = async (signal: AbortSignal) => {\n const response = await fetch(previewUrl.toString(), { signal });\n\n if (!response.ok) {\n throw new Error(`Sunboard preview failed with ${response.status}.`);\n }\n\n const json = (await response.json()) as NormalizedSunboardSpec;\n\n if (!isSunboardSpecLike(json)) {\n throw new Error(\"Sunboard preview returned an invalid spec payload.\");\n }\n\n return json;\n };\n\n setState({\n error: null,\n loading: true,\n source: \"none\",\n spec: null\n });\n\n loadSpec(controller.signal)\n .then((previewSpec) => {\n if (cancelled) return;\n\n setState({\n error: null,\n loading: false,\n source: \"preview\",\n spec: previewSpec\n });\n\n const eventsUrl = buildEventsUrl(previewUrl);\n if (eventsUrl && typeof EventSource !== \"undefined\") {\n eventSource = new EventSource(eventsUrl);\n let firstMessage = true;\n eventSource.onmessage = () => {\n // The sidecar sends the current version on connect; skip the\n // first message so we don't refetch the spec we just loaded.\n if (firstMessage) {\n firstMessage = false;\n return;\n }\n\n void reloadSpec(previewUrl);\n };\n eventSource.onerror = () => {\n // EventSource auto-reconnects with backoff. Nothing to do.\n };\n }\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted || cancelled) {\n return;\n }\n\n setState({\n error: error instanceof Error ? error : new Error(String(error)),\n loading: false,\n source: \"none\",\n spec: null\n });\n });\n\n const reloadSpec = async (url: URL) => {\n try {\n const response = await fetch(url.toString());\n\n if (!response.ok) {\n throw new Error(`Sunboard preview failed with ${response.status}.`);\n }\n\n const json = (await response.json()) as NormalizedSunboardSpec;\n\n if (!isSunboardSpecLike(json)) {\n throw new Error(\"Sunboard preview returned an invalid spec payload.\");\n }\n\n if (cancelled) return;\n\n setState({\n error: null,\n loading: false,\n source: \"preview\",\n spec: json\n });\n } catch (error) {\n if (cancelled) return;\n // Keep the existing spec on transient reload failure; surface the\n // error in state so dev tools can show it.\n setState((current) => ({\n ...current,\n error: error instanceof Error ? error : new Error(String(error))\n }));\n }\n };\n\n return () => {\n cancelled = true;\n controller.abort();\n eventSource?.close();\n };\n }, []);\n\n return state;\n}\n\nfunction buildEventsUrl(specUrl: URL): string | null {\n try {\n const eventsUrl = new URL(specUrl.toString());\n eventsUrl.pathname = eventsUrl.pathname.replace(/\\/spec\\.json$/, \"/events\");\n if (eventsUrl.pathname === specUrl.pathname) {\n return null;\n }\n return eventsUrl.toString();\n } catch {\n return null;\n }\n}\n\nfunction getPreviewSpecUrl(): URL | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n const pageUrl = new URL(window.location.href);\n\n if (pageUrl.searchParams.get(\"sunboard_preview\") !== \"1\") {\n return null;\n }\n\n const previewUrlParam = pageUrl.searchParams.get(\"sunboard_preview_url\");\n\n if (!previewUrlParam) {\n return null;\n }\n\n try {\n const previewUrl = new URL(previewUrlParam);\n return isAllowedLocalPreviewUrl(previewUrl) ? previewUrl : null;\n } catch {\n return null;\n }\n}\n\nfunction isAllowedLocalPreviewUrl(url: URL): boolean {\n return (\n url.protocol === \"http:\" &&\n (url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\")\n );\n}\n\nfunction isSunboardSpecLike(value: unknown): value is NormalizedSunboardSpec {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<NormalizedSunboardSpec>;\n\n return (\n typeof candidate.key === \"string\" &&\n typeof candidate.name === \"string\" &&\n typeof candidate.type === \"string\" &&\n typeof candidate.checklist === \"object\" &&\n Array.isArray(candidate.checklist?.steps)\n );\n}\n","export const SDK_VERSION = \"0.0.0\";\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction\n} from \"react\";\nimport type {\n NormalizedSunboardSpec,\n SunboardStep,\n TrackEventName\n} from \"@sunboard/core\";\nimport {\n SunboardRuntimeClient,\n type RuntimeExperience,\n type RuntimeProgress\n} from \"@sunboard/core/runtime-api\";\nimport {\n navigateWithFallback,\n type NavigateCallback\n} from \"../adapters/navigation\";\nimport { routeMatches } from \"../adapters/routes\";\nimport {\n SunboardContext,\n type ActiveSunboardTour,\n type SunboardContextValue,\n type SunboardRuntimeMode,\n type SunboardTourError,\n type SunboardUser,\n type TrackProperties\n} from \"../hooks/sunboard-context\";\nimport { useSunboardPreviewSpec } from \"../hooks/useSunboardPreviewSpec\";\nimport { SDK_VERSION } from \"../version\";\n\nexport type SunboardProviderProps = {\n spec?: NormalizedSunboardSpec | null;\n user?: SunboardUser | null;\n loading?: boolean;\n mode?: SunboardRuntimeMode;\n route?: string;\n navigate?: NavigateCallback;\n apiUrl?: string;\n publishableKey?: string;\n environment?: string;\n onTrack?: (\n eventName: TrackEventName,\n properties?: TrackProperties\n ) => void | Promise<void>;\n children: ReactNode;\n};\n\ntype ActiveTourState = {\n key: string;\n stepIndex: number;\n};\n\ntype BootstrapState = {\n experience: RuntimeExperience | null;\n loading: boolean;\n};\n\nexport function SunboardProvider({\n spec: specProp,\n user,\n loading: loadingProp,\n mode: modeProp,\n route,\n navigate,\n apiUrl,\n publishableKey,\n environment = \"production\",\n onTrack,\n children\n}: SunboardProviderProps) {\n const currentRoute = route ?? getBrowserRoute();\n const currentOrigin = getBrowserOrigin();\n const preview = useSunboardPreviewSpec();\n const client = useMemo(() => {\n if (!apiUrl || !publishableKey) {\n return null;\n }\n\n return new SunboardRuntimeClient({\n apiUrl,\n publishableKey,\n sdkVersion: SDK_VERSION\n });\n }, [apiUrl, publishableKey]);\n const bootstrap = useSunboardBootstrap(client, {\n enabled:\n !specProp && preview.source !== \"preview\" && !preview.loading,\n environment,\n origin: currentOrigin,\n route: currentRoute,\n user\n });\n\n const activeExperience = bootstrap.experience;\n const hostedSpec = activeExperience?.spec ?? null;\n const resolvedSpec = specProp ?? preview.spec ?? hostedSpec;\n const resolvedLoading =\n loadingProp ?? (preview.loading || bootstrap.loading);\n const resolvedMode: SunboardRuntimeMode =\n modeProp ?? (preview.source === \"preview\" ? \"preview\" : \"production\");\n const hostedMode = client !== null && !specProp && preview.source !== \"preview\";\n\n const [completedStepKeys, setCompletedStepKeys] = useState<Set<string>>(\n () => new Set()\n );\n const [completedTourKeys, setCompletedTourKeys] = useState<Set<string>>(\n () => new Set()\n );\n const [activeTourState, setActiveTourState] = useState<ActiveTourState | null>(\n null\n );\n const [tourError, setTourError] = useState<SunboardTourError | null>(null);\n const lastNavigatedTourStep = useRef<string | null>(null);\n const storageKey =\n !hostedMode && resolvedSpec && user\n ? completedToursStorageKey(resolvedSpec.key, user.id)\n : null;\n const experienceKey = activeExperience?.key ?? resolvedSpec?.key ?? null;\n const versionId = activeExperience?.version.id ?? null;\n\n useEffect(() => {\n setCompletedStepKeys(new Set());\n setActiveTourState(null);\n setTourError(null);\n lastNavigatedTourStep.current = null;\n\n if (!storageKey) {\n setCompletedTourKeys(new Set());\n return;\n }\n\n setCompletedTourKeys(readCompletedTours(storageKey));\n }, [resolvedSpec?.key, storageKey, user?.id]);\n\n useEffect(() => {\n if (!hostedMode || !activeExperience) {\n return;\n }\n\n applyProgress(\n activeExperience.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n }, [activeExperience, hostedMode]);\n\n const effectiveCompletedStepKeys = useMemo(() => {\n if (!hostedMode || !activeExperience) {\n return completedStepKeys;\n }\n\n return mergeKeys(\n completedStepKeys,\n activeExperience.progress.completedStepKeys\n );\n }, [activeExperience, completedStepKeys, hostedMode]);\n\n const effectiveCompletedTourKeys = useMemo(() => {\n if (!hostedMode || !activeExperience) {\n return completedTourKeys;\n }\n\n return mergeKeys(\n completedTourKeys,\n activeExperience.progress.completedTourKeys\n );\n }, [activeExperience, completedTourKeys, hostedMode]);\n\n useEffect(() => {\n if (!resolvedSpec) {\n return;\n }\n\n const tourCompletedStepKeys = resolvedSpec.checklist.steps\n .filter(\n (step) =>\n step.completeWhen?.tour &&\n effectiveCompletedTourKeys.has(step.completeWhen.tour)\n )\n .map((step) => step.key);\n\n if (tourCompletedStepKeys.length === 0) {\n return;\n }\n\n setCompletedStepKeys((current) => {\n const next = new Set(current);\n\n for (const stepKey of tourCompletedStepKeys) {\n next.add(stepKey);\n }\n\n return next;\n });\n }, [effectiveCompletedTourKeys, resolvedSpec]);\n\n const activeTour = useMemo<ActiveSunboardTour | null>(() => {\n if (!resolvedSpec || !activeTourState) {\n return null;\n }\n\n const tour = resolvedSpec.tours[activeTourState.key];\n const step = tour?.steps[activeTourState.stepIndex];\n\n if (!tour || !step) {\n return null;\n }\n\n return {\n key: activeTourState.key,\n name: tour.name,\n step,\n stepIndex: activeTourState.stepIndex,\n totalSteps: tour.steps.length\n };\n }, [activeTourState, resolvedSpec]);\n\n useEffect(() => {\n if (!activeTour?.step.route || routeMatches(activeTour.step.route, currentRoute)) {\n return;\n }\n\n const navigationKey = `${activeTour.key}:${activeTour.step.key}:${activeTour.step.route}`;\n\n if (lastNavigatedTourStep.current === navigationKey) {\n return;\n }\n\n lastNavigatedTourStep.current = navigationKey;\n void navigateWithFallback(activeTour.step.route, navigate);\n }, [activeTour, currentRoute, navigate]);\n\n // Record per-step tour progress. Fires once per (tour, step) transition;\n // the dep array tracks step.key + tour key so re-renders don't spam the\n // endpoint and re-entries refresh `lastSeenAt` server-side.\n useEffect(() => {\n if (\n !hostedMode ||\n !client ||\n !activeTour ||\n !user ||\n !experienceKey\n ) {\n return;\n }\n\n void client\n .recordTourStep({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n stepKey: activeTour.step.key,\n tourKey: activeTour.key,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n })\n .catch(() => {\n // Best-effort tracking — never break the host app on a 4xx/5xx.\n });\n // Intentionally narrow deps to the tour/step identity. We do not refire\n // when `currentRoute` changes mid-step, because the route adapter scrolls\n // the same popover into a new viewport, not a new logical step.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTour?.key, activeTour?.step.key, client, currentOrigin, experienceKey, hostedMode, user?.id]);\n\n const totalSteps = resolvedSpec?.checklist.steps.length ?? 0;\n const completedCount =\n resolvedSpec?.checklist.steps.filter((step) =>\n effectiveCompletedStepKeys.has(step.key)\n ).length ?? 0;\n\n const completeTour = useCallback(\n (tourKey: string) => {\n setCompletedTourKeys((current) => {\n const next = new Set(current);\n next.add(tourKey);\n\n if (storageKey) {\n writeCompletedTours(storageKey, next);\n }\n\n return next;\n });\n },\n [storageKey]\n );\n\n const track = useCallback<SunboardContextValue[\"track\"]>(\n async (eventName, properties) => {\n if (resolvedLoading || !resolvedSpec) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n const matchingStepKeys = resolvedSpec.checklist.steps\n .filter((step) => step.completeWhen?.event === eventName)\n .map((step) => step.key);\n\n if (matchingStepKeys.length > 0) {\n setCompletedStepKeys((current) => {\n const next = new Set(current);\n\n for (const stepKey of matchingStepKeys) {\n next.add(stepKey);\n }\n\n return next;\n });\n }\n\n let networkOk = true;\n\n if (hostedMode && client && experienceKey) {\n try {\n const response = await client.track({\n environment,\n eventName,\n experienceKey,\n origin: currentOrigin,\n properties,\n route: currentRoute,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n });\n applyProgress(\n response.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n } catch {\n networkOk = false;\n }\n }\n\n try {\n await onTrack?.(eventName, properties);\n } catch {\n return { ok: false, reason: \"network-error\" };\n }\n\n if (!networkOk) {\n return { ok: false, reason: \"network-error\" };\n }\n\n return { ok: true };\n },\n [\n client,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n onTrack,\n resolvedLoading,\n resolvedSpec,\n user,\n versionId\n ]\n );\n\n const navigateToStep = useCallback(\n async (step: SunboardStep) => {\n if (!step.route) {\n return;\n }\n\n await navigateWithFallback(step.route, navigate);\n },\n [navigate]\n );\n\n const startTour = useCallback<SunboardContextValue[\"startTour\"]>(\n async (tourKey) => {\n if (resolvedLoading || !resolvedSpec) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n if (!resolvedSpec.tours[tourKey]) {\n return { ok: false, reason: \"missing-tour\" };\n }\n\n setTourError(null);\n lastNavigatedTourStep.current = null;\n setActiveTourState({ key: tourKey, stepIndex: 0 });\n\n // Fire-and-forget tour-start. The per-step record fires from the\n // useEffect below when activeTour resolves, so step[0] gets recorded\n // independently. We deliberately don't await — popover UX must not\n // block on network.\n if (hostedMode && client && experienceKey && user) {\n void client\n .startTour({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n tourKey,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n })\n .catch(() => {\n // Tracking is best-effort. Network failures shouldn't surface\n // to the host app.\n });\n }\n\n return { ok: true };\n },\n [\n client,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n resolvedLoading,\n resolvedSpec,\n user,\n versionId\n ]\n );\n\n const dismissTour = useCallback<SunboardContextValue[\"dismissTour\"]>(\n async () => {\n setActiveTourState(null);\n setTourError(null);\n lastNavigatedTourStep.current = null;\n return { ok: true };\n },\n []\n );\n\n const finishActiveTour = useCallback(\n async (tourKey: string) => {\n completeTour(tourKey);\n\n if (!hostedMode || !client || !experienceKey || !user) {\n return;\n }\n\n try {\n const response = await client.completeTour({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n tourKey,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n });\n applyProgress(\n response.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n } catch {\n // Fail soft: keep local optimistic completion, never break the host app.\n }\n },\n [\n client,\n completeTour,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n user,\n versionId\n ]\n );\n\n const advanceTour = useCallback<SunboardContextValue[\"advanceTour\"]>(\n async () => {\n if (resolvedLoading || !resolvedSpec || !activeTourState) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n const tour = resolvedSpec.tours[activeTourState.key];\n\n if (!tour) {\n return { ok: false, reason: \"missing-tour\" };\n }\n\n setTourError(null);\n lastNavigatedTourStep.current = null;\n\n if (activeTourState.stepIndex >= tour.steps.length - 1) {\n const completedKey = activeTourState.key;\n setActiveTourState(null);\n await finishActiveTour(completedKey);\n return { ok: true };\n }\n\n setActiveTourState({\n key: activeTourState.key,\n stepIndex: activeTourState.stepIndex + 1\n });\n return { ok: true };\n },\n [activeTourState, finishActiveTour, resolvedLoading, resolvedSpec, user]\n );\n\n const startChecklistStep = useCallback<\n SunboardContextValue[\"startChecklistStep\"]\n >(\n async (step) => {\n if (step.action?.type === \"startTour\") {\n return startTour(step.action.tour);\n }\n\n await navigateToStep(step);\n },\n [navigateToStep, startTour]\n );\n\n const visibleHotspots = useMemo<SunboardContextValue[\"visibleHotspots\"]>(() => {\n if (!resolvedSpec || activeTour) {\n return [];\n }\n\n return Object.entries(resolvedSpec.hotspots)\n .filter(([, hotspot]) => routeMatches(hotspot.route, currentRoute))\n .filter(\n ([, hotspot]) =>\n hotspot.repeatable ||\n !effectiveCompletedTourKeys.has(hotspot.action.tour)\n )\n .map(([key, hotspot]) => ({ key, hotspot }));\n }, [activeTour, effectiveCompletedTourKeys, currentRoute, resolvedSpec]);\n\n const reportTourError = useCallback((error: SunboardTourError | null) => {\n setTourError(error);\n }, []);\n\n const value = useMemo<SunboardContextValue>(\n () => ({\n spec: resolvedSpec,\n user,\n loading: resolvedLoading,\n mode: resolvedMode,\n route: currentRoute,\n completedStepKeys: effectiveCompletedStepKeys,\n completedTourKeys: effectiveCompletedTourKeys,\n completedCount,\n totalSteps,\n activeTour,\n tourError,\n track,\n startTour,\n dismissTour,\n advanceTour,\n navigateToStep,\n startChecklistStep,\n reportTourError,\n visibleHotspots\n }),\n [\n resolvedSpec,\n user,\n resolvedLoading,\n resolvedMode,\n currentRoute,\n effectiveCompletedStepKeys,\n effectiveCompletedTourKeys,\n completedCount,\n totalSteps,\n activeTour,\n tourError,\n track,\n startTour,\n dismissTour,\n advanceTour,\n navigateToStep,\n startChecklistStep,\n reportTourError,\n visibleHotspots\n ]\n );\n\n return (\n <SunboardContext.Provider value={value}>\n {children}\n </SunboardContext.Provider>\n );\n}\n\nfunction useSunboardBootstrap(\n client: SunboardRuntimeClient | null,\n options: {\n enabled: boolean;\n environment: string;\n origin?: string;\n route: string;\n user?: SunboardUser | null;\n }\n): BootstrapState {\n const { enabled, environment, origin, route, user } = options;\n const [state, setState] = useState<BootstrapState>({\n experience: null,\n loading: false\n });\n const warnedSdkAdvisory = useRef(false);\n\n useEffect(() => {\n if (!client || !enabled || !user?.id) {\n setState({ experience: null, loading: false });\n return;\n }\n\n // TODO: plumb `controller.signal` through SunboardRuntimeClient.post into\n // the underlying fetch so aborted requests cancel at the network layer. In\n // React 19 dev StrictMode the provider mounts twice; the first effect's\n // fetch keeps flying and can surface as `TypeError: Failed to fetch` in the\n // browser console. Harmless (we guard with signal.aborted before touching\n // state) but noisy in dev.\n const controller = new AbortController();\n setState({ experience: null, loading: true });\n\n client\n .bootstrap({\n environment,\n origin,\n route,\n user: toRuntimeUser(user)\n })\n .then((response) => {\n if (controller.signal.aborted) {\n return;\n }\n\n if (response.experiences.length === 0 && isDevEnvironment()) {\n console.warn(\n `[sunboard] bootstrap returned no active experiences for route \"${route}\" in environment \"${environment}\". Check the dashboard for an enabled deployment whose trigger.route matches.`\n );\n }\n\n if (\n response.sdkAdvisory &&\n isDevEnvironment() &&\n !warnedSdkAdvisory.current\n ) {\n warnedSdkAdvisory.current = true;\n console.warn(`[sunboard] ${response.sdkAdvisory.message}`);\n }\n\n setState({\n experience: response.experiences[0] ?? null,\n loading: false\n });\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) {\n return;\n }\n\n if (isDevEnvironment()) {\n console.warn(\"[sunboard] bootstrap failed\", error);\n }\n\n setState({ experience: null, loading: false });\n });\n\n return () => {\n controller.abort();\n };\n // user.id is the identity key; we deliberately do not refetch when the\n // user object reference changes without an id change. `route` is\n // intentionally excluded so navigation does not wipe the active experience\n // — per-route visibility is handled by the runtime via step/tour/hotspot\n // route matching.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, enabled, environment, origin, user?.id]);\n\n return state;\n}\n\nfunction applyProgress(\n progress: RuntimeProgress,\n setSteps: Dispatch<SetStateAction<Set<string>>>,\n setTours: Dispatch<SetStateAction<Set<string>>>\n) {\n setSteps((current) => mergeKeys(current, progress.completedStepKeys));\n setTours((current) => mergeKeys(current, progress.completedTourKeys));\n}\n\nfunction mergeKeys(current: Set<string>, incoming: string[]): Set<string> {\n if (incoming.length === 0) {\n return current;\n }\n\n const next = new Set(current);\n\n for (const key of incoming) {\n next.add(key);\n }\n\n if (next.size === current.size) {\n return current;\n }\n\n return next;\n}\n\nfunction isDevEnvironment(): boolean {\n if (typeof process === \"undefined\" || !process.env) {\n return false;\n }\n\n return process.env.NODE_ENV !== \"production\";\n}\n\nfunction toRuntimeUser(user: SunboardUser) {\n return {\n email: user.email ?? undefined,\n group: user.group ?? undefined,\n id: user.id,\n properties: user.properties\n };\n}\n\nfunction completedToursStorageKey(specKey: string, userId: string): string {\n return `sunboard:${specKey}:${userId}:completed-tours`;\n}\n\nfunction getBrowserRoute(): string {\n if (typeof window === \"undefined\") {\n return \"/\";\n }\n\n return `${window.location.pathname}${window.location.search}`;\n}\n\nfunction getBrowserOrigin(): string | undefined {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n return window.location.origin;\n}\n\nfunction readCompletedTours(storageKey: string): Set<string> {\n if (typeof window === \"undefined\") {\n return new Set();\n }\n\n try {\n const rawValue = window.localStorage.getItem(storageKey);\n const parsed = rawValue ? (JSON.parse(rawValue) as unknown) : [];\n\n if (!Array.isArray(parsed)) {\n return new Set();\n }\n\n return new Set(parsed.filter((value): value is string => typeof value === \"string\"));\n } catch {\n return new Set();\n }\n}\n\nfunction writeCompletedTours(storageKey: string, tourKeys: Set<string>) {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.setItem(storageKey, JSON.stringify([...tourKeys].sort()));\n } catch {\n // Ignore storage failures; persistence should never break the host app.\n }\n}\n","import type { SunboardUser } from \"../hooks/sunboard-context\";\n\nconst TOKEN_PATTERN =\n /\\{\\{\\s*user\\.([\\w][\\w.]*)(?:\\s*\\|\\s*(?:\"([^\"]*)\"|'([^']*)'))?\\s*\\}\\}/g;\n\ntype FlatUser = Record<string, unknown>;\n\nfunction flattenUser(user: SunboardUser | null | undefined): FlatUser {\n if (!user) return {};\n const properties = (user.properties ?? {}) as Record<string, unknown>;\n const flat: FlatUser = { ...properties };\n flat.id = user.id;\n if (user.email !== undefined) flat.email = user.email;\n if (user.group !== undefined) flat.group = user.group;\n return flat;\n}\n\nfunction lookupPath(root: FlatUser, path: string): unknown {\n const segments = path.split(\".\");\n let current: unknown = root;\n for (const segment of segments) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nfunction coerceValue(value: unknown): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") return value.length > 0 ? value : null;\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return null;\n}\n\nexport function interpolateTokens(\n template: string,\n user: SunboardUser | null | undefined\n): string {\n if (!template || !template.includes(\"{{\")) return template;\n const flat = flattenUser(user);\n return template.replace(\n TOKEN_PATTERN,\n (_match, path: string, doubleQuoted?: string, singleQuoted?: string) => {\n const resolved = coerceValue(lookupPath(flat, path));\n if (resolved !== null) return resolved;\n const fallback = doubleQuoted ?? singleQuoted;\n return fallback ?? \"\";\n }\n );\n}\n\nexport function extractUserTokens(template: string): string[] {\n if (!template || !template.includes(\"{{\")) return [];\n const paths: string[] = [];\n TOKEN_PATTERN.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = TOKEN_PATTERN.exec(template)) !== null) {\n const path = match[1];\n if (path) paths.push(path);\n }\n return paths;\n}\n","import { useContext } from \"react\";\nimport { SunboardContext, type SunboardContextValue } from \"./sunboard-context\";\n\nexport function useSunboard(): SunboardContextValue {\n const context = useContext(SunboardContext);\n\n if (!context) {\n throw new Error(\"useSunboard must be used within SunboardProvider.\");\n }\n\n return context;\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\r\nimport type { SunboardStep } from \"@sunboard/core\";\r\nimport { interpolateTokens } from \"../lib/interpolate-tokens\";\r\nimport { useSunboard } from \"./useSunboard\";\r\n\r\nexport type ChecklistViewStep = {\r\n key: string;\r\n title: string;\r\n description?: string;\r\n badge?: string;\r\n actionLabel?: string;\r\n};\r\n\r\nexport type ChecklistCompletion = {\r\n title: string;\r\n subtitle?: string;\r\n message?: string;\r\n dismissAfterMs?: number;\r\n};\r\n\r\nexport type UseChecklistResult = {\r\n visible: boolean;\r\n title?: string;\r\n subtitle?: string;\r\n steps: ChecklistViewStep[];\r\n completedStepKeys: ReadonlySet<string>;\r\n completedCount: number;\r\n totalSteps: number;\r\n remainingCount: number;\r\n progress: number;\r\n isCompleted: (key: string) => boolean;\r\n hasAction: (step: ChecklistViewStep) => boolean;\r\n startStep: (step: ChecklistViewStep) => void;\r\n completion?: ChecklistCompletion;\r\n dismissCompletion: () => void;\r\n};\r\n\r\nconst SUPPORTED_CHECKLIST_TYPES = new Set([\"checklist\", \"hybrid\"]);\r\n\r\nfunction actionLabelFor(step: SunboardStep): string | undefined {\r\n if (step.action?.type === \"startTour\") return \"Start\";\r\n if (step.action || step.route) return \"Open\";\r\n return undefined;\r\n}\r\n\r\nfunction interpolateOptional(\r\n text: string | undefined,\r\n user: Parameters<typeof interpolateTokens>[1]\r\n): string | undefined {\r\n if (!text) return undefined;\r\n const interpolated = interpolateTokens(text, user);\r\n return interpolated || undefined;\r\n}\r\n\r\nexport function useChecklist(): UseChecklistResult {\r\n const {\r\n spec,\r\n user,\r\n loading,\r\n completedStepKeys,\r\n completedCount,\r\n totalSteps,\r\n startChecklistStep\r\n } = useSunboard();\r\n\r\n const [dismissedKey, setDismissedKey] = useState<string | null>(null);\r\n\r\n const hasChecklist = Boolean(spec && SUPPORTED_CHECKLIST_TYPES.has(spec.type));\r\n const allCompleted = totalSteps > 0 && completedCount >= totalSteps;\r\n const ready = !loading && !!user && !!spec && hasChecklist;\r\n\r\n // The completion screen celebrates the *transition* from incomplete to\r\n // complete in this session — not the steady \"already done\" state. The server\r\n // already knows per-user completion via bootstrap, so a user who finished\r\n // on another device sees `allCompleted === true` from the first ready\r\n // render and we suppress the celebration. We only show it if we observed\r\n // them being incomplete first.\r\n //\r\n // Scoped to (spec, user) so switching either restarts the observation.\n const specKey = spec?.key ?? null;\n const userId = user?.id ?? null;\n const observationKey =\n ready && specKey && userId ? `${specKey}:${userId}` : null;\n const observationRef = useRef<{ key: string; sawIncomplete: boolean } | null>(\n null\n );\n if (observationKey && observationRef.current?.key !== observationKey) {\n observationRef.current = {\n key: observationKey,\n sawIncomplete: !allCompleted\n };\n } else if (observationKey && observationRef.current && !allCompleted) {\n observationRef.current.sawIncomplete = true;\n }\n const sawIncompleteFirst = observationRef.current?.sawIncomplete ?? false;\r\n\r\n const dismissed = dismissedKey !== null && dismissedKey === observationKey;\r\n\r\n const rawSteps = useMemo<SunboardStep[]>(\r\n () => spec?.checklist?.steps ?? [],\r\n [spec]\r\n );\r\n\r\n const title = useMemo(\r\n () => interpolateOptional(spec?.title, user ?? null),\r\n [spec?.title, user]\r\n );\r\n\r\n const subtitle = useMemo(\r\n () => interpolateOptional(spec?.subtitle, user ?? null),\r\n [spec?.subtitle, user]\r\n );\r\n\r\n const completion = useMemo<ChecklistCompletion | undefined>(() => {\r\n const raw = spec?.completion;\r\n if (!raw) return undefined;\r\n const interpolatedTitle = interpolateOptional(raw.title, user ?? null);\r\n if (!interpolatedTitle) return undefined;\r\n return {\r\n title: interpolatedTitle,\r\n subtitle: interpolateOptional(raw.subtitle, user ?? null),\r\n message: interpolateOptional(raw.message, user ?? null),\r\n dismissAfterMs: raw.dismissAfterMs\r\n };\r\n }, [spec?.completion, user]);\r\n\r\n const showingCompletion =\r\n ready && allCompleted && !!completion && sawIncompleteFirst && !dismissed;\r\n const visible = (ready && !allCompleted) || showingCompletion;\r\n\r\n const steps = useMemo<ChecklistViewStep[]>(() => {\r\n return rawSteps.map((step) => ({\r\n key: step.key,\r\n title: interpolateTokens(step.title, user ?? null),\r\n description: step.description\r\n ? interpolateTokens(step.description, user ?? null)\r\n : undefined,\r\n badge: step.badge\r\n ? interpolateTokens(step.badge, user ?? null)\r\n : undefined,\r\n actionLabel: actionLabelFor(step)\r\n }));\r\n }, [rawSteps, user]);\r\n\r\n const stepsByKey = useMemo(() => {\r\n const map = new Map<string, SunboardStep>();\r\n for (const step of rawSteps) {\r\n map.set(step.key, step);\r\n }\r\n return map;\r\n }, [rawSteps]);\r\n\r\n const remainingCount = Math.max(totalSteps - completedCount, 0);\r\n const progress =\r\n totalSteps > 0 ? Math.round((completedCount / totalSteps) * 100) : 0;\r\n\r\n const dismissCompletion = useCallback(() => {\r\n if (observationKey) {\r\n setDismissedKey(observationKey);\r\n }\r\n }, [observationKey]);\r\n\r\n return {\r\n visible,\r\n title,\r\n subtitle,\r\n steps,\r\n completedStepKeys,\r\n completedCount,\r\n totalSteps,\r\n remainingCount,\r\n progress,\r\n isCompleted: (key) => completedStepKeys.has(key),\r\n hasAction: (step) => step.actionLabel !== undefined,\r\n startStep: (step) => {\r\n const raw = stepsByKey.get(step.key);\r\n if (raw) {\r\n void startChecklistStep(raw);\r\n }\r\n },\r\n completion: showingCompletion ? completion : undefined,\r\n dismissCompletion\r\n };\r\n}\r\n","\r\nexport const CheckIcon = () => {\r\n return <svg xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\r\n className=\"lucide lucide-check-icon lucide-check\"><path d=\"M20 6 9 17l-5-5\" /></svg>\r\n}","import { CheckIcon } from \"../icons\";\nimport type { ChecklistViewStep } from \"../hooks/useChecklist\";\n\ntype ChecklistStepProps = {\n completed: boolean;\n onStart: () => void;\n step: ChecklistViewStep;\n};\n\nexport function ChecklistStep({\n completed,\n onStart,\n step\n}: ChecklistStepProps) {\n const hasAction = step.actionLabel !== undefined;\n\n const status = (\n <span\n className=\"sunboard-step-status\"\n aria-label={completed ? \"Completed\" : \"Incomplete\"}\n >\n {completed ? <CheckIcon /> : null}\n </span>\n );\n\n const content = (\n <div className=\"sunboard-step-content\">\n <div className=\"sunboard-step-heading\">\n <h3 className=\"sunboard-step-title\">{step.title}</h3>\n {step.badge ? (\n <span className=\"sunboard-step-badge\">{step.badge}</span>\n ) : null}\n </div>\n\n {step.description ? (\n <p className=\"sunboard-step-description\">{step.description}</p>\n ) : null}\n </div>\n );\n\n return (\n <li className=\"sunboard-step\" data-completed={completed}>\n {hasAction ? (\n <button\n className=\"sunboard-step-row\"\n type=\"button\"\n onClick={onStart}\n aria-label={`${step.actionLabel} ${step.title}`}\n >\n {status}\n {content}\n </button>\n ) : (\n <div className=\"sunboard-step-row\">\n {status}\n {content}\n </div>\n )}\n </li>\n );\n}\n","import { useMemo } from \"react\";\nimport { interpolateTokens } from \"../lib/interpolate-tokens\";\nimport { useSunboard } from \"./useSunboard\";\n\nexport function useInterpolated(text: string): string;\nexport function useInterpolated(text: string | undefined): string | undefined;\nexport function useInterpolated(text: string | undefined): string | undefined {\n const { user } = useSunboard();\n return useMemo(() => {\n if (text === undefined) return undefined;\n return interpolateTokens(text, user);\n }, [text, user]);\n}\n","import { useEffect, useState } from \"react\";\n\nexport type TargetElementState = {\n element: HTMLElement | null;\n timedOut: boolean;\n};\n\nexport function useTargetElement(\n selector: string | null,\n enabled: boolean,\n timeoutMs = 5_000\n): TargetElementState {\n const [state, setState] = useState<TargetElementState>({\n element: null,\n timedOut: false\n });\n\n useEffect(() => {\n if (!enabled || !selector) {\n setState({ element: null, timedOut: false });\n return;\n }\n\n let cancelled = false;\n const startedAt = Date.now();\n\n const findTarget = () => {\n if (cancelled) {\n return;\n }\n\n const element = document.querySelector(selector);\n\n if (element instanceof HTMLElement) {\n setState({ element, timedOut: false });\n return;\n }\n\n if (Date.now() - startedAt >= timeoutMs) {\n setState({ element: null, timedOut: true });\n return;\n }\n\n window.setTimeout(findTarget, 100);\n };\n\n setState({ element: null, timedOut: false });\n findTarget();\n\n return () => {\n cancelled = true;\n };\n }, [enabled, selector, timeoutMs]);\n\n return state;\n}\n","import {\r\n FloatingPortal,\r\n autoUpdate,\r\n offset,\r\n useFloating\r\n} from \"@floating-ui/react\";\r\nimport { useEffect } from \"react\";\r\nimport type { SunboardHotspot } from \"@sunboard/core\";\r\nimport { useInterpolated } from \"../hooks/useInterpolated\";\r\nimport { useSunboard } from \"../hooks/useSunboard\";\r\nimport { useTargetElement } from \"../hooks/useTargetElement\";\r\n\r\ntype HotspotProps = {\r\n hotspot: SunboardHotspot;\r\n hotspotKey: string;\r\n};\r\n\r\nconst HOTSPOT_RADIUS_PX = 9;\r\n\r\nexport function SunboardHotspots() {\r\n const { visibleHotspots } = useSunboard();\r\n\r\n return (\r\n <>\r\n {visibleHotspots.map(({ key, hotspot }) => (\r\n <Hotspot hotspot={hotspot} hotspotKey={key} key={key} />\r\n ))}\r\n </>\r\n );\r\n}\r\n\r\nfunction Hotspot({ hotspot, hotspotKey }: HotspotProps) {\r\n const { startTour } = useSunboard();\r\n const label = useInterpolated(hotspot.label);\r\n const target = useTargetElement(hotspot.target, true);\r\n const { refs, floatingStyles } = useFloating({\r\n placement: hotspot.placement,\r\n strategy: \"fixed\",\r\n middleware: [offset(-HOTSPOT_RADIUS_PX)],\r\n whileElementsMounted: autoUpdate\r\n });\r\n\r\n useEffect(() => {\r\n if (!target.element) {\r\n return;\r\n }\r\n\r\n refs.setReference(target.element);\r\n }, [refs, target.element]);\r\n\r\n if (!target.element) {\r\n return null;\r\n }\r\n\r\n return (\r\n <FloatingPortal>\r\n <button\r\n aria-label={label ?? `Start ${hotspot.action.tour} tour`}\r\n className=\"sunboard-hotspot\"\r\n data-pulse={hotspot.pulse}\r\n data-sunboard-hotspot={hotspotKey}\r\n onClick={() => {\r\n void startTour(hotspot.action.tour);\r\n }}\r\n ref={refs.setFloating}\r\n style={floatingStyles}\r\n type=\"button\"\r\n >\r\n <span className=\"sunboard-hotspot-dot\" />\r\n </button>\r\n </FloatingPortal>\r\n );\r\n}\r\n","import {\r\n arrow,\r\n FloatingArrow,\r\n FloatingPortal,\r\n flip,\r\n offset,\r\n shift,\r\n useFloating\r\n} from \"@floating-ui/react\";\r\nimport { useEffect, useRef, useState } from \"react\";\r\nimport { routeMatches } from \"../adapters/routes\";\r\nimport { useInterpolated } from \"../hooks/useInterpolated\";\r\nimport { useSunboard } from \"../hooks/useSunboard\";\r\nimport { useTargetElement } from \"../hooks/useTargetElement\";\r\n\r\nexport function SunboardTour() {\r\n const {\r\n activeTour,\r\n advanceTour,\r\n dismissTour,\r\n mode,\r\n reportTourError,\r\n route,\r\n tourError\r\n } = useSunboard();\r\n const arrowRef = useRef<SVGSVGElement | null>(null);\r\n const [spotlightRect, setSpotlightRect] = useState<DOMRect | null>(null);\r\n const routeReady = routeMatches(activeTour?.step.route, route ?? \"/\");\r\n const target = useTargetElement(\r\n activeTour?.step.target ?? null,\r\n Boolean(activeTour) && routeReady,\r\n 1_000\r\n );\r\n const { context, refs, floatingStyles, update } = useFloating({\r\n placement: activeTour?.step.placement ?? \"bottom\",\r\n middleware: [\r\n offset(16),\r\n flip(),\r\n shift({ padding: 12 }),\r\n arrow({ element: arrowRef })\r\n ]\r\n });\r\n\r\n useEffect(() => {\r\n if (!activeTour) {\r\n reportTourError(null);\r\n return;\r\n }\r\n\r\n if (!routeReady) {\r\n return;\r\n }\r\n\r\n if (!target.timedOut) {\r\n return;\r\n }\r\n\r\n const error = {\r\n message: \"Sunboard could not find the tour target.\",\r\n route: activeTour.step.route,\r\n stepKey: activeTour.step.key,\r\n target: activeTour.step.target,\r\n tourKey: activeTour.key\r\n };\r\n\r\n if (mode === \"preview\") {\r\n reportTourError(error);\r\n return;\r\n }\r\n\r\n reportTourError(null);\r\n void dismissTour();\r\n }, [activeTour, dismissTour, mode, reportTourError, routeReady, target.timedOut]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n return;\r\n }\r\n\r\n reportTourError(null);\r\n refs.setReference(target.element);\r\n target.element.scrollIntoView({ block: \"center\", inline: \"center\" });\r\n void update();\r\n }, [activeTour, refs, reportTourError, target.element, update]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n setSpotlightRect(null);\r\n return;\r\n }\r\n\r\n const updateSpotlight = () => {\r\n setSpotlightRect(target.element?.getBoundingClientRect() ?? null);\r\n };\r\n\r\n updateSpotlight();\r\n window.addEventListener(\"resize\", updateSpotlight);\r\n window.addEventListener(\"scroll\", updateSpotlight, true);\r\n\r\n target.element.setAttribute(\"data-sunboard-tour-target\", \"true\");\r\n\r\n return () => {\r\n window.removeEventListener(\"resize\", updateSpotlight);\r\n window.removeEventListener(\"scroll\", updateSpotlight, true);\r\n target.element?.removeAttribute(\"data-sunboard-tour-target\");\r\n setSpotlightRect(null);\r\n };\r\n }, [activeTour, target.element]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n return;\r\n }\r\n\r\n const advanceOnTargetClick = () => {\r\n window.setTimeout(() => {\r\n void advanceTour();\r\n }, 0);\r\n };\r\n\r\n target.element.addEventListener(\"click\", advanceOnTargetClick);\r\n\r\n return () => {\r\n target.element?.removeEventListener(\"click\", advanceOnTargetClick);\r\n };\r\n }, [activeTour, advanceTour, target.element]);\r\n\r\n const tourName = useInterpolated(activeTour?.name);\r\n const stepTitle = useInterpolated(activeTour?.step.title);\r\n const stepBody = useInterpolated(activeTour?.step.body);\r\n\r\n if (!activeTour) {\r\n return null;\r\n }\r\n\r\n if (tourError && mode === \"preview\") {\r\n return (\r\n <div className=\"sunboard-debug\" role=\"alert\">\r\n <strong>{tourError.message}</strong>\r\n <span>Tour: {tourError.tourKey}</span>\r\n <span>Step: {tourError.stepKey}</span>\r\n {tourError.route ? <span>Route: {tourError.route}</span> : null}\r\n {tourError.target ? <span>Target: {tourError.target}</span> : null}\r\n <button onClick={() => void dismissTour()} type=\"button\">\r\n Dismiss\r\n </button>\r\n </div>\r\n );\r\n }\r\n\r\n if (!routeReady || !target.element) {\r\n return null;\r\n }\r\n\r\n const isLastStep = activeTour.stepIndex === activeTour.totalSteps - 1;\r\n\r\n return (\r\n <FloatingPortal>\r\n <SunboardTourScrim rect={spotlightRect} />\r\n <section\r\n aria-label={`${tourName} tour step`}\r\n className=\"sunboard-tour\"\r\n ref={refs.setFloating}\r\n role=\"dialog\"\r\n style={floatingStyles}\r\n >\r\n <FloatingArrow\r\n className=\"sunboard-tour-arrow\"\r\n context={context}\r\n fill=\"var(--sunboard-tour-background)\"\r\n ref={arrowRef}\r\n stroke=\"var(--sunboard-tour-border)\"\r\n strokeWidth={1}\r\n tipRadius={2}\r\n />\r\n <div className=\"sunboard-tour-meta\">\r\n {activeTour.stepIndex + 1} / {activeTour.totalSteps}\r\n </div>\r\n <h2 className=\"sunboard-tour-title\">{stepTitle}</h2>\r\n {stepBody ? (\r\n <p className=\"sunboard-tour-body\">{stepBody}</p>\r\n ) : null}\r\n <div className=\"sunboard-tour-actions\">\r\n <button\r\n className=\"sunboard-tour-secondary\"\r\n onClick={() => void dismissTour()}\r\n type=\"button\"\r\n >\r\n Dismiss\r\n </button>\r\n <button\r\n className=\"sunboard-tour-primary\"\r\n onClick={() => void advanceTour()}\r\n type=\"button\"\r\n >\r\n {isLastStep ? \"Finish\" : \"Next\"}\r\n </button>\r\n </div>\r\n </section>\r\n </FloatingPortal>\r\n );\r\n}\r\n\r\nfunction SunboardTourScrim({ rect }: { rect: DOMRect | null }) {\r\n if (!rect) {\r\n return <div className=\"sunboard-tour-scrim\" />;\r\n }\r\n\r\n const padding = 8;\r\n const radius = 12;\r\n const left = Math.max(rect.left - padding, 0);\r\n const top = Math.max(rect.top - padding, 0);\r\n const width = rect.width + padding * 2;\r\n const height = rect.height + padding * 2;\r\n const maskId = \"sunboard-tour-spotlight-mask\";\r\n\r\n return (\r\n <svg\r\n aria-hidden=\"true\"\r\n className=\"sunboard-tour-scrim sunboard-tour-spotlight\"\r\n focusable=\"false\"\r\n >\r\n <defs>\r\n <mask id={maskId}>\r\n <rect fill=\"white\" height=\"100%\" width=\"100%\" x=\"0\" y=\"0\" />\r\n <rect\r\n fill=\"black\"\r\n height={height}\r\n rx={radius}\r\n ry={radius}\r\n width={width}\r\n x={left}\r\n y={top}\r\n />\r\n </mask>\r\n </defs>\r\n <rect\r\n fill=\"var(--sunboard-overlay-color)\"\r\n height=\"100%\"\r\n mask={`url(#${maskId})`}\r\n width=\"100%\"\r\n x=\"0\"\r\n y=\"0\"\r\n />\r\n </svg>\r\n );\r\n}\r\n","import { useEffect, useState } from \"react\";\r\nimport { useChecklist } from \"../hooks/useChecklist\";\r\nimport { ChecklistStep } from \"./ChecklistStep\";\r\nimport { SunboardHotspots } from \"./SunboardHotspots\";\r\nimport { SunboardTour } from \"./SunboardTour\";\r\n\r\nexport function SunboardChecklist() {\r\n const [open, setOpen] = useState(true);\r\n const {\r\n visible,\r\n title,\r\n subtitle,\r\n steps,\r\n completedCount,\r\n totalSteps,\r\n remainingCount,\r\n progress,\r\n isCompleted,\r\n startStep,\r\n completion,\r\n dismissCompletion\r\n } = useChecklist();\r\n\r\n // Auto-dismiss the completion screen after the spec-author-specified delay.\r\n // Lives in the widget rather than the hook so custom checklists can choose\r\n // their own timing UX (e.g. dismiss on tab change) without inheriting ours.\r\n useEffect(() => {\r\n if (!completion?.dismissAfterMs) return;\r\n const handle = window.setTimeout(dismissCompletion, completion.dismissAfterMs);\r\n return () => window.clearTimeout(handle);\r\n }, [completion, dismissCompletion]);\r\n\r\n if (!visible || !title) {\r\n return null;\r\n }\r\n\r\n if (completion) {\r\n return (\r\n <aside\r\n className=\"sunboard-root sunboard-root-completion\"\r\n aria-label={`${title} complete`}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n >\r\n <button\r\n className=\"sunboard-close sunboard-completion-close\"\r\n type=\"button\"\r\n onClick={dismissCompletion}\r\n aria-label=\"Dismiss completion message\"\r\n >\r\n x\r\n </button>\r\n <div className=\"sunboard-completion\">\r\n <div className=\"sunboard-completion-check\" aria-hidden=\"true\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"3\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polyline points=\"5 12 10 17 19 8\" />\r\n </svg>\r\n </div>\r\n {completion.subtitle ? (\r\n <p className=\"sunboard-completion-subtitle\">{completion.subtitle}</p>\r\n ) : null}\r\n <h2 className=\"sunboard-completion-title\">{completion.title}</h2>\r\n {completion.message ? (\r\n <p className=\"sunboard-completion-message\">{completion.message}</p>\r\n ) : null}\r\n </div>\r\n </aside>\r\n );\r\n }\r\n\r\n if (!open) {\r\n return (\r\n <button\r\n className=\"sunboard-launcher\"\r\n type=\"button\"\r\n onClick={() => setOpen(true)}\r\n aria-label={`Open ${title} checklist, ${remainingCount} tasks remaining`}\r\n >\r\n <span className=\"sunboard-launcher-count\">{remainingCount}</span>\r\n </button>\r\n );\r\n }\r\n\r\n return (\r\n <aside className=\"sunboard-root\" aria-label={`${title} checklist`}>\r\n <div className=\"sunboard-header\">\r\n <div>\r\n {subtitle ? <p className=\"sunboard-eyebrow\">{subtitle}</p> : null}\r\n <h2 className=\"sunboard-title\">{title}</h2>\r\n </div>\r\n <div className=\"sunboard-header-actions\">\r\n <p\r\n className=\"sunboard-progress-count\"\r\n aria-label=\"Checklist progress\"\r\n >\r\n {completedCount} / {totalSteps}\r\n </p>\r\n <button\r\n className=\"sunboard-close\"\r\n type=\"button\"\r\n onClick={() => setOpen(false)}\r\n aria-label={`Close ${title} checklist`}\r\n >\r\n x\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div\r\n className=\"sunboard-progress\"\r\n role=\"progressbar\"\r\n aria-label={`${title} progress`}\r\n aria-valuemin={0}\r\n aria-valuemax={totalSteps}\r\n aria-valuenow={completedCount}\r\n >\r\n <div\r\n className=\"sunboard-progress-fill\"\r\n style={{ width: `${progress}%` }}\r\n />\r\n </div>\r\n\r\n <ol className=\"sunboard-step-list\">\r\n {steps.map((step) => (\r\n <ChecklistStep\r\n completed={isCompleted(step.key)}\r\n key={step.key}\r\n onStart={() => startStep(step)}\r\n step={step}\r\n />\r\n ))}\r\n </ol>\r\n </aside>\r\n );\r\n}\r\n\r\nexport const Sunboard = Object.assign(SunboardChecklist, {\r\n Checklist: SunboardChecklist,\r\n Hotspots: SunboardHotspots,\r\n Tour: SunboardTour\r\n});\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["eventSource: EventSource | null","SunboardRuntimeClient","resolvedMode: SunboardRuntimeMode","flat: FlatUser","current: unknown"],"sources":["../src/adapters/navigation.ts","../src/hooks/sunboard-context.ts","../src/hooks/useSunboardPreviewSpec.ts","../src/version.ts","../src/components/SunboardProvider.tsx","../src/lib/interpolate-tokens.ts","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts","../src/icons/index.tsx","../src/components/ChecklistStep.tsx","../src/hooks/useInterpolated.ts","../src/hooks/useTargetElement.ts","../src/components/SunboardHotspots.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx"],"sourcesContent":["export type NavigateCallback = (url: string) => void | Promise<void>;\n\nexport async function navigateWithFallback(\n url: string,\n navigate?: NavigateCallback\n): Promise<void> {\n if (navigate) {\n await navigate(url);\n return;\n }\n\n if (typeof window !== \"undefined\") {\n window.location.assign(url);\n }\n}\n","import { createContext } from \"react\";\nimport type {\n NormalizedSunboardSpec,\n SunboardHotspot,\n SunboardStep,\n SunboardTourStep,\n TrackEventName\n} from \"@sunboard/core\";\n\nexport type SunboardUser = {\n id: string;\n email?: string | null;\n group?: string | null;\n properties?: Record<string, unknown>;\n};\n\nexport type TrackProperties = Record<string, unknown>;\n\nexport type TrackResult =\n | { ok: true }\n | { ok: false; reason: \"not-ready\" | \"missing-user\" | \"network-error\" };\n\nexport type TourResult =\n | { ok: true }\n | { ok: false; reason: \"not-ready\" | \"missing-user\" | \"missing-tour\" };\n\nexport type SunboardRuntimeMode = \"production\" | \"preview\";\n\nexport type SunboardTourError = {\n message: string;\n route?: string;\n stepKey?: string;\n target?: string;\n tourKey: string;\n};\n\nexport type ActiveSunboardTour = {\n key: string;\n name: string;\n step: SunboardTourStep;\n stepIndex: number;\n totalSteps: number;\n};\n\nexport type SunboardContextValue = {\n spec?: NormalizedSunboardSpec | null;\n user?: SunboardUser | null;\n loading: boolean;\n route?: string;\n mode: SunboardRuntimeMode;\n completedStepKeys: ReadonlySet<string>;\n completedTourKeys: ReadonlySet<string>;\n completedCount: number;\n totalSteps: number;\n activeTour: ActiveSunboardTour | null;\n tourError: SunboardTourError | null;\n track: (\n eventName: TrackEventName,\n properties?: TrackProperties\n ) => Promise<TrackResult>;\n startTour: (tourKey: string) => Promise<TourResult>;\n dismissTour: () => Promise<TourResult>;\n advanceTour: () => Promise<TourResult>;\n navigateToStep: (step: SunboardStep) => Promise<void>;\n startChecklistStep: (step: SunboardStep) => Promise<TourResult | void>;\n reportTourError: (error: SunboardTourError | null) => void;\n visibleHotspots: Array<{ key: string; hotspot: SunboardHotspot }>;\n};\n\nexport const SunboardContext = createContext<SunboardContextValue | null>(null);\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { NormalizedSunboardSpec } from \"@sunboard/core\";\n\nexport type SunboardPreviewSpecState = {\n error: Error | null;\n loading: boolean;\n source: \"none\" | \"preview\";\n spec: NormalizedSunboardSpec | null;\n};\n\nexport function useSunboardPreviewSpec(): SunboardPreviewSpecState {\n const [state, setState] = useState<SunboardPreviewSpecState>(() => ({\n error: null,\n loading: getPreviewSpecUrl() !== null,\n source: \"none\",\n spec: null\n }));\n\n useEffect(() => {\n const previewUrl = getPreviewSpecUrl();\n\n if (!previewUrl) {\n setState({\n error: null,\n loading: false,\n source: \"none\",\n spec: null\n });\n return;\n }\n\n const controller = new AbortController();\n let cancelled = false;\n let eventSource: EventSource | null = null;\n\n const loadSpec = async (signal: AbortSignal) => {\n const response = await fetch(previewUrl.toString(), { signal });\n\n if (!response.ok) {\n throw new Error(`Sunboard preview failed with ${response.status}.`);\n }\n\n const json = (await response.json()) as NormalizedSunboardSpec;\n\n if (!isSunboardSpecLike(json)) {\n throw new Error(\"Sunboard preview returned an invalid spec payload.\");\n }\n\n return json;\n };\n\n setState({\n error: null,\n loading: true,\n source: \"none\",\n spec: null\n });\n\n loadSpec(controller.signal)\n .then((previewSpec) => {\n if (cancelled) return;\n\n setState({\n error: null,\n loading: false,\n source: \"preview\",\n spec: previewSpec\n });\n\n const eventsUrl = buildEventsUrl(previewUrl);\n if (eventsUrl && typeof EventSource !== \"undefined\") {\n eventSource = new EventSource(eventsUrl);\n let firstMessage = true;\n eventSource.onmessage = () => {\n // The sidecar sends the current version on connect; skip the\n // first message so we don't refetch the spec we just loaded.\n if (firstMessage) {\n firstMessage = false;\n return;\n }\n\n void reloadSpec(previewUrl);\n };\n eventSource.onerror = () => {\n // EventSource auto-reconnects with backoff. Nothing to do.\n };\n }\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted || cancelled) {\n return;\n }\n\n setState({\n error: error instanceof Error ? error : new Error(String(error)),\n loading: false,\n source: \"none\",\n spec: null\n });\n });\n\n const reloadSpec = async (url: URL) => {\n try {\n const response = await fetch(url.toString());\n\n if (!response.ok) {\n throw new Error(`Sunboard preview failed with ${response.status}.`);\n }\n\n const json = (await response.json()) as NormalizedSunboardSpec;\n\n if (!isSunboardSpecLike(json)) {\n throw new Error(\"Sunboard preview returned an invalid spec payload.\");\n }\n\n if (cancelled) return;\n\n setState({\n error: null,\n loading: false,\n source: \"preview\",\n spec: json\n });\n } catch (error) {\n if (cancelled) return;\n // Keep the existing spec on transient reload failure; surface the\n // error in state so dev tools can show it.\n setState((current) => ({\n ...current,\n error: error instanceof Error ? error : new Error(String(error))\n }));\n }\n };\n\n return () => {\n cancelled = true;\n controller.abort();\n eventSource?.close();\n };\n }, []);\n\n return state;\n}\n\nfunction buildEventsUrl(specUrl: URL): string | null {\n try {\n const eventsUrl = new URL(specUrl.toString());\n eventsUrl.pathname = eventsUrl.pathname.replace(/\\/spec\\.json$/, \"/events\");\n if (eventsUrl.pathname === specUrl.pathname) {\n return null;\n }\n return eventsUrl.toString();\n } catch {\n return null;\n }\n}\n\nfunction getPreviewSpecUrl(): URL | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n const pageUrl = new URL(window.location.href);\n\n if (pageUrl.searchParams.get(\"sunboard_preview\") !== \"1\") {\n return null;\n }\n\n const previewUrlParam = pageUrl.searchParams.get(\"sunboard_preview_url\");\n\n if (!previewUrlParam) {\n return null;\n }\n\n try {\n const previewUrl = new URL(previewUrlParam);\n return isAllowedLocalPreviewUrl(previewUrl) ? previewUrl : null;\n } catch {\n return null;\n }\n}\n\nfunction isAllowedLocalPreviewUrl(url: URL): boolean {\n return (\n url.protocol === \"http:\" &&\n (url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\")\n );\n}\n\nfunction isSunboardSpecLike(value: unknown): value is NormalizedSunboardSpec {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<NormalizedSunboardSpec>;\n\n return (\n typeof candidate.key === \"string\" &&\n typeof candidate.name === \"string\" &&\n typeof candidate.type === \"string\" &&\n typeof candidate.checklist === \"object\" &&\n Array.isArray(candidate.checklist?.steps)\n );\n}\n","export const SDK_VERSION = \"0.0.0\";\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction\n} from \"react\";\nimport type {\n NormalizedSunboardSpec,\n SunboardStep,\n TrackEventName\n} from \"@sunboard/core\";\nimport {\n DEFAULT_RUNTIME_API_URL,\n SunboardRuntimeClient,\n type RuntimeExperience,\n type RuntimeProgress\n} from \"@sunboard/core/runtime-api\";\nimport {\n navigateWithFallback,\n type NavigateCallback\n} from \"../adapters/navigation\";\nimport { routeMatches } from \"../adapters/routes\";\nimport {\n SunboardContext,\n type ActiveSunboardTour,\n type SunboardContextValue,\n type SunboardRuntimeMode,\n type SunboardTourError,\n type SunboardUser,\n type TrackProperties\n} from \"../hooks/sunboard-context\";\nimport { useSunboardPreviewSpec } from \"../hooks/useSunboardPreviewSpec\";\nimport { SDK_VERSION } from \"../version\";\n\nexport type SunboardProviderProps = {\n spec?: NormalizedSunboardSpec | null;\n user?: SunboardUser | null;\n loading?: boolean;\n mode?: SunboardRuntimeMode;\n route?: string;\n navigate?: NavigateCallback;\n /**\n * Override the runtime API host. Dev-only — leave unset in production so the\n * SDK targets the hosted Sunboard runtime API. Defaults to\n * `DEFAULT_RUNTIME_API_URL`.\n */\n apiUrl?: string;\n publishableKey?: string;\n environment?: string;\n onTrack?: (\n eventName: TrackEventName,\n properties?: TrackProperties\n ) => void | Promise<void>;\n children: ReactNode;\n};\n\ntype ActiveTourState = {\n key: string;\n stepIndex: number;\n};\n\ntype BootstrapState = {\n experience: RuntimeExperience | null;\n loading: boolean;\n};\n\nexport function SunboardProvider({\n spec: specProp,\n user,\n loading: loadingProp,\n mode: modeProp,\n route,\n navigate,\n apiUrl,\n publishableKey,\n environment = \"production\",\n onTrack,\n children\n}: SunboardProviderProps) {\n const currentRoute = route ?? getBrowserRoute();\n const currentOrigin = getBrowserOrigin();\n const preview = useSunboardPreviewSpec();\n const client = useMemo(() => {\n if (!publishableKey) {\n return null;\n }\n\n // `apiUrl` is a dev-only override; production apps only supply a key and\n // talk to the hosted runtime API by default.\n return new SunboardRuntimeClient({\n apiUrl: apiUrl || DEFAULT_RUNTIME_API_URL,\n publishableKey,\n sdkVersion: SDK_VERSION\n });\n }, [apiUrl, publishableKey]);\n const bootstrap = useSunboardBootstrap(client, {\n enabled:\n !specProp && preview.source !== \"preview\" && !preview.loading,\n environment,\n origin: currentOrigin,\n route: currentRoute,\n user\n });\n\n const activeExperience = bootstrap.experience;\n const hostedSpec = activeExperience?.spec ?? null;\n const resolvedSpec = specProp ?? preview.spec ?? hostedSpec;\n const resolvedLoading =\n loadingProp ?? (preview.loading || bootstrap.loading);\n const resolvedMode: SunboardRuntimeMode =\n modeProp ?? (preview.source === \"preview\" ? \"preview\" : \"production\");\n const hostedMode = client !== null && !specProp && preview.source !== \"preview\";\n\n const [completedStepKeys, setCompletedStepKeys] = useState<Set<string>>(\n () => new Set()\n );\n const [completedTourKeys, setCompletedTourKeys] = useState<Set<string>>(\n () => new Set()\n );\n const [activeTourState, setActiveTourState] = useState<ActiveTourState | null>(\n null\n );\n const [tourError, setTourError] = useState<SunboardTourError | null>(null);\n const lastNavigatedTourStep = useRef<string | null>(null);\n const storageKey =\n !hostedMode && resolvedSpec && user\n ? completedToursStorageKey(resolvedSpec.key, user.id)\n : null;\n const experienceKey = activeExperience?.key ?? resolvedSpec?.key ?? null;\n const versionId = activeExperience?.version.id ?? null;\n\n useEffect(() => {\n setCompletedStepKeys(new Set());\n setActiveTourState(null);\n setTourError(null);\n lastNavigatedTourStep.current = null;\n\n if (!storageKey) {\n setCompletedTourKeys(new Set());\n return;\n }\n\n setCompletedTourKeys(readCompletedTours(storageKey));\n }, [resolvedSpec?.key, storageKey, user?.id]);\n\n useEffect(() => {\n if (!hostedMode || !activeExperience) {\n return;\n }\n\n applyProgress(\n activeExperience.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n }, [activeExperience, hostedMode]);\n\n const effectiveCompletedStepKeys = useMemo(() => {\n if (!hostedMode || !activeExperience) {\n return completedStepKeys;\n }\n\n return mergeKeys(\n completedStepKeys,\n activeExperience.progress.completedStepKeys\n );\n }, [activeExperience, completedStepKeys, hostedMode]);\n\n const effectiveCompletedTourKeys = useMemo(() => {\n if (!hostedMode || !activeExperience) {\n return completedTourKeys;\n }\n\n return mergeKeys(\n completedTourKeys,\n activeExperience.progress.completedTourKeys\n );\n }, [activeExperience, completedTourKeys, hostedMode]);\n\n useEffect(() => {\n if (!resolvedSpec) {\n return;\n }\n\n const tourCompletedStepKeys = resolvedSpec.checklist.steps\n .filter(\n (step) =>\n step.completeWhen?.tour &&\n effectiveCompletedTourKeys.has(step.completeWhen.tour)\n )\n .map((step) => step.key);\n\n if (tourCompletedStepKeys.length === 0) {\n return;\n }\n\n setCompletedStepKeys((current) => mergeKeys(current, tourCompletedStepKeys));\n }, [effectiveCompletedTourKeys, resolvedSpec]);\n\n const activeTour = useMemo<ActiveSunboardTour | null>(() => {\n if (!resolvedSpec || !activeTourState) {\n return null;\n }\n\n const tour = resolvedSpec.tours[activeTourState.key];\n const step = tour?.steps[activeTourState.stepIndex];\n\n if (!tour || !step) {\n return null;\n }\n\n return {\n key: activeTourState.key,\n name: tour.name,\n step,\n stepIndex: activeTourState.stepIndex,\n totalSteps: tour.steps.length\n };\n }, [activeTourState, resolvedSpec]);\n\n useEffect(() => {\n if (!activeTour?.step.route || routeMatches(activeTour.step.route, currentRoute)) {\n return;\n }\n\n const navigationKey = `${activeTour.key}:${activeTour.step.key}:${activeTour.step.route}`;\n\n if (lastNavigatedTourStep.current === navigationKey) {\n return;\n }\n\n lastNavigatedTourStep.current = navigationKey;\n void navigateWithFallback(activeTour.step.route, navigate);\n }, [activeTour, currentRoute, navigate]);\n\n // Record per-step tour progress. Fires once per (tour, step) transition;\n // the dep array tracks step.key + tour key so re-renders don't spam the\n // endpoint and re-entries refresh `lastSeenAt` server-side.\n useEffect(() => {\n if (\n !hostedMode ||\n !client ||\n !activeTour ||\n !user ||\n !experienceKey\n ) {\n return;\n }\n\n void client\n .recordTourStep({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n stepKey: activeTour.step.key,\n tourKey: activeTour.key,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n })\n .catch(() => {\n // Best-effort tracking — never break the host app on a 4xx/5xx.\n });\n // Intentionally narrow deps to the tour/step identity. We do not refire\n // when `currentRoute` changes mid-step, because the route adapter scrolls\n // the same popover into a new viewport, not a new logical step.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTour?.key, activeTour?.step.key, client, currentOrigin, experienceKey, hostedMode, user?.id]);\n\n const totalSteps = resolvedSpec?.checklist.steps.length ?? 0;\n const completedCount =\n resolvedSpec?.checklist.steps.filter((step) =>\n effectiveCompletedStepKeys.has(step.key)\n ).length ?? 0;\n\n const completeTour = useCallback(\n (tourKey: string) => {\n setCompletedTourKeys((current) => {\n const next = new Set(current);\n next.add(tourKey);\n\n if (storageKey) {\n writeCompletedTours(storageKey, next);\n }\n\n return next;\n });\n },\n [storageKey]\n );\n\n const track = useCallback<SunboardContextValue[\"track\"]>(\n async (eventName, properties) => {\n if (resolvedLoading || !resolvedSpec) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n const matchingStepKeys = resolvedSpec.checklist.steps\n .filter((step) => step.completeWhen?.event === eventName)\n .map((step) => step.key);\n\n if (matchingStepKeys.length > 0) {\n // `mergeKeys` returns `current` unchanged when every key is already\n // present, so re-firing an already-completed step's event is a no-op\n // and does not churn state/recreate the context value. This is what\n // keeps a consumer that calls `track()` from an effect depending on the\n // whole context value from looping render→track→render.\n setCompletedStepKeys((current) => mergeKeys(current, matchingStepKeys));\n }\n\n let networkOk = true;\n\n if (hostedMode && client && experienceKey) {\n try {\n const response = await client.track({\n environment,\n eventName,\n experienceKey,\n origin: currentOrigin,\n properties,\n route: currentRoute,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n });\n applyProgress(\n response.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n } catch {\n networkOk = false;\n }\n }\n\n try {\n await onTrack?.(eventName, properties);\n } catch {\n return { ok: false, reason: \"network-error\" };\n }\n\n if (!networkOk) {\n return { ok: false, reason: \"network-error\" };\n }\n\n return { ok: true };\n },\n [\n client,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n onTrack,\n resolvedLoading,\n resolvedSpec,\n user,\n versionId\n ]\n );\n\n const navigateToStep = useCallback(\n async (step: SunboardStep) => {\n if (!step.route) {\n return;\n }\n\n await navigateWithFallback(step.route, navigate);\n },\n [navigate]\n );\n\n const startTour = useCallback<SunboardContextValue[\"startTour\"]>(\n async (tourKey) => {\n if (resolvedLoading || !resolvedSpec) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n if (!resolvedSpec.tours[tourKey]) {\n return { ok: false, reason: \"missing-tour\" };\n }\n\n setTourError(null);\n lastNavigatedTourStep.current = null;\n setActiveTourState({ key: tourKey, stepIndex: 0 });\n\n // Fire-and-forget tour-start. The per-step record fires from the\n // useEffect below when activeTour resolves, so step[0] gets recorded\n // independently. We deliberately don't await — popover UX must not\n // block on network.\n if (hostedMode && client && experienceKey && user) {\n void client\n .startTour({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n tourKey,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n })\n .catch(() => {\n // Tracking is best-effort. Network failures shouldn't surface\n // to the host app.\n });\n }\n\n return { ok: true };\n },\n [\n client,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n resolvedLoading,\n resolvedSpec,\n user,\n versionId\n ]\n );\n\n const dismissTour = useCallback<SunboardContextValue[\"dismissTour\"]>(\n async () => {\n setActiveTourState(null);\n setTourError(null);\n lastNavigatedTourStep.current = null;\n return { ok: true };\n },\n []\n );\n\n const finishActiveTour = useCallback(\n async (tourKey: string) => {\n completeTour(tourKey);\n\n if (!hostedMode || !client || !experienceKey || !user) {\n return;\n }\n\n try {\n const response = await client.completeTour({\n environment,\n experienceKey,\n origin: currentOrigin,\n route: currentRoute,\n tourKey,\n user: toRuntimeUser(user),\n versionId: versionId ?? undefined\n });\n applyProgress(\n response.progress,\n setCompletedStepKeys,\n setCompletedTourKeys\n );\n } catch {\n // Fail soft: keep local optimistic completion, never break the host app.\n }\n },\n [\n client,\n completeTour,\n currentRoute,\n currentOrigin,\n environment,\n experienceKey,\n hostedMode,\n user,\n versionId\n ]\n );\n\n const advanceTour = useCallback<SunboardContextValue[\"advanceTour\"]>(\n async () => {\n if (resolvedLoading || !resolvedSpec || !activeTourState) {\n return { ok: false, reason: \"not-ready\" };\n }\n\n if (!user) {\n return { ok: false, reason: \"missing-user\" };\n }\n\n const tour = resolvedSpec.tours[activeTourState.key];\n\n if (!tour) {\n return { ok: false, reason: \"missing-tour\" };\n }\n\n setTourError(null);\n lastNavigatedTourStep.current = null;\n\n if (activeTourState.stepIndex >= tour.steps.length - 1) {\n const completedKey = activeTourState.key;\n setActiveTourState(null);\n await finishActiveTour(completedKey);\n return { ok: true };\n }\n\n setActiveTourState({\n key: activeTourState.key,\n stepIndex: activeTourState.stepIndex + 1\n });\n return { ok: true };\n },\n [activeTourState, finishActiveTour, resolvedLoading, resolvedSpec, user]\n );\n\n const startChecklistStep = useCallback<\n SunboardContextValue[\"startChecklistStep\"]\n >(\n async (step) => {\n if (step.action?.type === \"startTour\") {\n return startTour(step.action.tour);\n }\n\n await navigateToStep(step);\n },\n [navigateToStep, startTour]\n );\n\n const visibleHotspots = useMemo<SunboardContextValue[\"visibleHotspots\"]>(() => {\n if (!resolvedSpec || activeTour) {\n return [];\n }\n\n return Object.entries(resolvedSpec.hotspots)\n .filter(([, hotspot]) => routeMatches(hotspot.route, currentRoute))\n .filter(\n ([, hotspot]) =>\n hotspot.repeatable ||\n !effectiveCompletedTourKeys.has(hotspot.action.tour)\n )\n .map(([key, hotspot]) => ({ key, hotspot }));\n }, [activeTour, effectiveCompletedTourKeys, currentRoute, resolvedSpec]);\n\n const reportTourError = useCallback((error: SunboardTourError | null) => {\n setTourError(error);\n }, []);\n\n const value = useMemo<SunboardContextValue>(\n () => ({\n spec: resolvedSpec,\n user,\n loading: resolvedLoading,\n mode: resolvedMode,\n route: currentRoute,\n completedStepKeys: effectiveCompletedStepKeys,\n completedTourKeys: effectiveCompletedTourKeys,\n completedCount,\n totalSteps,\n activeTour,\n tourError,\n track,\n startTour,\n dismissTour,\n advanceTour,\n navigateToStep,\n startChecklistStep,\n reportTourError,\n visibleHotspots\n }),\n [\n resolvedSpec,\n user,\n resolvedLoading,\n resolvedMode,\n currentRoute,\n effectiveCompletedStepKeys,\n effectiveCompletedTourKeys,\n completedCount,\n totalSteps,\n activeTour,\n tourError,\n track,\n startTour,\n dismissTour,\n advanceTour,\n navigateToStep,\n startChecklistStep,\n reportTourError,\n visibleHotspots\n ]\n );\n\n return (\n <SunboardContext.Provider value={value}>\n {children}\n </SunboardContext.Provider>\n );\n}\n\nfunction useSunboardBootstrap(\n client: SunboardRuntimeClient | null,\n options: {\n enabled: boolean;\n environment: string;\n origin?: string;\n route: string;\n user?: SunboardUser | null;\n }\n): BootstrapState {\n const { enabled, environment, origin, route, user } = options;\n const [state, setState] = useState<BootstrapState>({\n experience: null,\n loading: false\n });\n const warnedSdkAdvisory = useRef(false);\n\n useEffect(() => {\n if (!client || !enabled || !user?.id) {\n setState({ experience: null, loading: false });\n return;\n }\n\n // TODO: plumb `controller.signal` through SunboardRuntimeClient.post into\n // the underlying fetch so aborted requests cancel at the network layer. In\n // React 19 dev StrictMode the provider mounts twice; the first effect's\n // fetch keeps flying and can surface as `TypeError: Failed to fetch` in the\n // browser console. Harmless (we guard with signal.aborted before touching\n // state) but noisy in dev.\n const controller = new AbortController();\n setState({ experience: null, loading: true });\n\n client\n .bootstrap({\n environment,\n origin,\n route,\n user: toRuntimeUser(user)\n })\n .then((response) => {\n if (controller.signal.aborted) {\n return;\n }\n\n if (response.experiences.length === 0 && isDevEnvironment()) {\n console.warn(\n `[sunboard] bootstrap returned no active experiences for route \"${route}\" in environment \"${environment}\". Check the dashboard for an enabled deployment whose trigger.route matches.`\n );\n }\n\n if (\n response.sdkAdvisory &&\n isDevEnvironment() &&\n !warnedSdkAdvisory.current\n ) {\n warnedSdkAdvisory.current = true;\n console.warn(`[sunboard] ${response.sdkAdvisory.message}`);\n }\n\n setState({\n experience: response.experiences[0] ?? null,\n loading: false\n });\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) {\n return;\n }\n\n if (isDevEnvironment()) {\n console.warn(\"[sunboard] bootstrap failed\", error);\n }\n\n setState({ experience: null, loading: false });\n });\n\n return () => {\n controller.abort();\n };\n // user.id is the identity key; we deliberately do not refetch when the\n // user object reference changes without an id change. `route` is\n // intentionally excluded so navigation does not wipe the active experience\n // — per-route visibility is handled by the runtime via step/tour/hotspot\n // route matching.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, enabled, environment, origin, user?.id]);\n\n return state;\n}\n\nfunction applyProgress(\n progress: RuntimeProgress,\n setSteps: Dispatch<SetStateAction<Set<string>>>,\n setTours: Dispatch<SetStateAction<Set<string>>>\n) {\n setSteps((current) => mergeKeys(current, progress.completedStepKeys));\n setTours((current) => mergeKeys(current, progress.completedTourKeys));\n}\n\nfunction mergeKeys(current: Set<string>, incoming: string[]): Set<string> {\n if (incoming.length === 0) {\n return current;\n }\n\n const next = new Set(current);\n\n for (const key of incoming) {\n next.add(key);\n }\n\n if (next.size === current.size) {\n return current;\n }\n\n return next;\n}\n\nfunction isDevEnvironment(): boolean {\n if (typeof process === \"undefined\" || !process.env) {\n return false;\n }\n\n return process.env.NODE_ENV !== \"production\";\n}\n\nfunction toRuntimeUser(user: SunboardUser) {\n return {\n email: user.email ?? undefined,\n group: user.group ?? undefined,\n id: user.id,\n properties: user.properties\n };\n}\n\nfunction completedToursStorageKey(specKey: string, userId: string): string {\n return `sunboard:${specKey}:${userId}:completed-tours`;\n}\n\nfunction getBrowserRoute(): string {\n if (typeof window === \"undefined\") {\n return \"/\";\n }\n\n return `${window.location.pathname}${window.location.search}`;\n}\n\nfunction getBrowserOrigin(): string | undefined {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n return window.location.origin;\n}\n\nfunction readCompletedTours(storageKey: string): Set<string> {\n if (typeof window === \"undefined\") {\n return new Set();\n }\n\n try {\n const rawValue = window.localStorage.getItem(storageKey);\n const parsed = rawValue ? (JSON.parse(rawValue) as unknown) : [];\n\n if (!Array.isArray(parsed)) {\n return new Set();\n }\n\n return new Set(parsed.filter((value): value is string => typeof value === \"string\"));\n } catch {\n return new Set();\n }\n}\n\nfunction writeCompletedTours(storageKey: string, tourKeys: Set<string>) {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.setItem(storageKey, JSON.stringify([...tourKeys].sort()));\n } catch {\n // Ignore storage failures; persistence should never break the host app.\n }\n}\n","import type { SunboardUser } from \"../hooks/sunboard-context\";\n\nconst TOKEN_PATTERN =\n /\\{\\{\\s*user\\.([\\w][\\w.]*)(?:\\s*\\|\\s*(?:\"([^\"]*)\"|'([^']*)'))?\\s*\\}\\}/g;\n\ntype FlatUser = Record<string, unknown>;\n\nfunction flattenUser(user: SunboardUser | null | undefined): FlatUser {\n if (!user) return {};\n const properties = (user.properties ?? {}) as Record<string, unknown>;\n const flat: FlatUser = { ...properties };\n flat.id = user.id;\n if (user.email !== undefined) flat.email = user.email;\n if (user.group !== undefined) flat.group = user.group;\n return flat;\n}\n\nfunction lookupPath(root: FlatUser, path: string): unknown {\n const segments = path.split(\".\");\n let current: unknown = root;\n for (const segment of segments) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nfunction coerceValue(value: unknown): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") return value.length > 0 ? value : null;\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return null;\n}\n\nexport function interpolateTokens(\n template: string,\n user: SunboardUser | null | undefined\n): string {\n if (!template || !template.includes(\"{{\")) return template;\n const flat = flattenUser(user);\n return template.replace(\n TOKEN_PATTERN,\n (_match, path: string, doubleQuoted?: string, singleQuoted?: string) => {\n const resolved = coerceValue(lookupPath(flat, path));\n if (resolved !== null) return resolved;\n const fallback = doubleQuoted ?? singleQuoted;\n return fallback ?? \"\";\n }\n );\n}\n\nexport function extractUserTokens(template: string): string[] {\n if (!template || !template.includes(\"{{\")) return [];\n const paths: string[] = [];\n TOKEN_PATTERN.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = TOKEN_PATTERN.exec(template)) !== null) {\n const path = match[1];\n if (path) paths.push(path);\n }\n return paths;\n}\n","import { useContext } from \"react\";\nimport { SunboardContext, type SunboardContextValue } from \"./sunboard-context\";\n\nexport function useSunboard(): SunboardContextValue {\n const context = useContext(SunboardContext);\n\n if (!context) {\n throw new Error(\"useSunboard must be used within SunboardProvider.\");\n }\n\n return context;\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\r\nimport type { SunboardStep } from \"@sunboard/core\";\r\nimport { interpolateTokens } from \"../lib/interpolate-tokens\";\r\nimport { useSunboard } from \"./useSunboard\";\r\n\r\nexport type ChecklistViewStep = {\r\n key: string;\r\n title: string;\r\n description?: string;\r\n badge?: string;\r\n actionLabel?: string;\r\n};\r\n\r\nexport type ChecklistCompletion = {\r\n title: string;\r\n subtitle?: string;\r\n message?: string;\r\n dismissAfterMs?: number;\r\n};\r\n\r\nexport type UseChecklistResult = {\r\n visible: boolean;\r\n title?: string;\r\n subtitle?: string;\r\n steps: ChecklistViewStep[];\r\n completedStepKeys: ReadonlySet<string>;\r\n completedCount: number;\r\n totalSteps: number;\r\n remainingCount: number;\r\n progress: number;\r\n isCompleted: (key: string) => boolean;\r\n hasAction: (step: ChecklistViewStep) => boolean;\r\n startStep: (step: ChecklistViewStep) => void;\r\n completion?: ChecklistCompletion;\r\n dismissCompletion: () => void;\r\n};\r\n\r\nconst SUPPORTED_CHECKLIST_TYPES = new Set([\"checklist\", \"hybrid\"]);\r\n\r\nfunction actionLabelFor(step: SunboardStep): string | undefined {\r\n if (step.action?.type === \"startTour\") return \"Start\";\r\n if (step.action || step.route) return \"Open\";\r\n return undefined;\r\n}\r\n\r\nfunction interpolateOptional(\r\n text: string | undefined,\r\n user: Parameters<typeof interpolateTokens>[1]\r\n): string | undefined {\r\n if (!text) return undefined;\r\n const interpolated = interpolateTokens(text, user);\r\n return interpolated || undefined;\r\n}\r\n\r\nexport function useChecklist(): UseChecklistResult {\r\n const {\r\n spec,\r\n user,\r\n loading,\r\n completedStepKeys,\r\n completedCount,\r\n totalSteps,\r\n startChecklistStep\r\n } = useSunboard();\r\n\r\n const [dismissedKey, setDismissedKey] = useState<string | null>(null);\r\n\r\n const hasChecklist = Boolean(spec && SUPPORTED_CHECKLIST_TYPES.has(spec.type));\r\n const allCompleted = totalSteps > 0 && completedCount >= totalSteps;\r\n const ready = !loading && !!user && !!spec && hasChecklist;\r\n\r\n // The completion screen celebrates the *transition* from incomplete to\r\n // complete in this session — not the steady \"already done\" state. The server\r\n // already knows per-user completion via bootstrap, so a user who finished\r\n // on another device sees `allCompleted === true` from the first ready\r\n // render and we suppress the celebration. We only show it if we observed\r\n // them being incomplete first.\r\n //\r\n // Scoped to (spec, user) so switching either restarts the observation.\n const specKey = spec?.key ?? null;\n const userId = user?.id ?? null;\n const observationKey =\n ready && specKey && userId ? `${specKey}:${userId}` : null;\n const observationRef = useRef<{ key: string; sawIncomplete: boolean } | null>(\n null\n );\n if (observationKey && observationRef.current?.key !== observationKey) {\n observationRef.current = {\n key: observationKey,\n sawIncomplete: !allCompleted\n };\n } else if (observationKey && observationRef.current && !allCompleted) {\n observationRef.current.sawIncomplete = true;\n }\n const sawIncompleteFirst = observationRef.current?.sawIncomplete ?? false;\r\n\r\n const dismissed = dismissedKey !== null && dismissedKey === observationKey;\r\n\r\n const rawSteps = useMemo<SunboardStep[]>(\r\n () => spec?.checklist?.steps ?? [],\r\n [spec]\r\n );\r\n\r\n const title = useMemo(\r\n () => interpolateOptional(spec?.title, user ?? null),\r\n [spec?.title, user]\r\n );\r\n\r\n const subtitle = useMemo(\r\n () => interpolateOptional(spec?.subtitle, user ?? null),\r\n [spec?.subtitle, user]\r\n );\r\n\r\n const completion = useMemo<ChecklistCompletion | undefined>(() => {\r\n const raw = spec?.completion;\r\n if (!raw) return undefined;\r\n const interpolatedTitle = interpolateOptional(raw.title, user ?? null);\r\n if (!interpolatedTitle) return undefined;\r\n return {\r\n title: interpolatedTitle,\r\n subtitle: interpolateOptional(raw.subtitle, user ?? null),\r\n message: interpolateOptional(raw.message, user ?? null),\r\n dismissAfterMs: raw.dismissAfterMs\r\n };\r\n }, [spec?.completion, user]);\r\n\r\n const showingCompletion =\r\n ready && allCompleted && !!completion && sawIncompleteFirst && !dismissed;\r\n const visible = (ready && !allCompleted) || showingCompletion;\r\n\r\n const steps = useMemo<ChecklistViewStep[]>(() => {\r\n return rawSteps.map((step) => ({\r\n key: step.key,\r\n title: interpolateTokens(step.title, user ?? null),\r\n description: step.description\r\n ? interpolateTokens(step.description, user ?? null)\r\n : undefined,\r\n badge: step.badge\r\n ? interpolateTokens(step.badge, user ?? null)\r\n : undefined,\r\n actionLabel: actionLabelFor(step)\r\n }));\r\n }, [rawSteps, user]);\r\n\r\n const stepsByKey = useMemo(() => {\r\n const map = new Map<string, SunboardStep>();\r\n for (const step of rawSteps) {\r\n map.set(step.key, step);\r\n }\r\n return map;\r\n }, [rawSteps]);\r\n\r\n const remainingCount = Math.max(totalSteps - completedCount, 0);\r\n const progress =\r\n totalSteps > 0 ? Math.round((completedCount / totalSteps) * 100) : 0;\r\n\r\n const dismissCompletion = useCallback(() => {\r\n if (observationKey) {\r\n setDismissedKey(observationKey);\r\n }\r\n }, [observationKey]);\r\n\r\n return {\r\n visible,\r\n title,\r\n subtitle,\r\n steps,\r\n completedStepKeys,\r\n completedCount,\r\n totalSteps,\r\n remainingCount,\r\n progress,\r\n isCompleted: (key) => completedStepKeys.has(key),\r\n hasAction: (step) => step.actionLabel !== undefined,\r\n startStep: (step) => {\r\n const raw = stepsByKey.get(step.key);\r\n if (raw) {\r\n void startChecklistStep(raw);\r\n }\r\n },\r\n completion: showingCompletion ? completion : undefined,\r\n dismissCompletion\r\n };\r\n}\r\n","\r\nexport const CheckIcon = () => {\r\n return <svg xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\r\n className=\"lucide lucide-check-icon lucide-check\"><path d=\"M20 6 9 17l-5-5\" /></svg>\r\n}","import { CheckIcon } from \"../icons\";\nimport type { ChecklistViewStep } from \"../hooks/useChecklist\";\n\ntype ChecklistStepProps = {\n completed: boolean;\n onStart: () => void;\n step: ChecklistViewStep;\n};\n\nexport function ChecklistStep({\n completed,\n onStart,\n step\n}: ChecklistStepProps) {\n const hasAction = step.actionLabel !== undefined;\n\n const status = (\n <span\n className=\"sunboard-step-status\"\n aria-label={completed ? \"Completed\" : \"Incomplete\"}\n >\n {completed ? <CheckIcon /> : null}\n </span>\n );\n\n const content = (\n <div className=\"sunboard-step-content\">\n <div className=\"sunboard-step-heading\">\n <h3 className=\"sunboard-step-title\">{step.title}</h3>\n {step.badge ? (\n <span className=\"sunboard-step-badge\">{step.badge}</span>\n ) : null}\n </div>\n\n {step.description ? (\n <p className=\"sunboard-step-description\">{step.description}</p>\n ) : null}\n </div>\n );\n\n return (\n <li className=\"sunboard-step\" data-completed={completed}>\n {hasAction ? (\n <button\n className=\"sunboard-step-row\"\n type=\"button\"\n onClick={onStart}\n aria-label={`${step.actionLabel} ${step.title}`}\n >\n {status}\n {content}\n </button>\n ) : (\n <div className=\"sunboard-step-row\">\n {status}\n {content}\n </div>\n )}\n </li>\n );\n}\n","import { useMemo } from \"react\";\nimport { interpolateTokens } from \"../lib/interpolate-tokens\";\nimport { useSunboard } from \"./useSunboard\";\n\nexport function useInterpolated(text: string): string;\nexport function useInterpolated(text: string | undefined): string | undefined;\nexport function useInterpolated(text: string | undefined): string | undefined {\n const { user } = useSunboard();\n return useMemo(() => {\n if (text === undefined) return undefined;\n return interpolateTokens(text, user);\n }, [text, user]);\n}\n","import { useEffect, useState } from \"react\";\n\nexport type TargetElementState = {\n element: HTMLElement | null;\n timedOut: boolean;\n};\n\nexport function useTargetElement(\n selector: string | null,\n enabled: boolean,\n timeoutMs = 5_000\n): TargetElementState {\n const [state, setState] = useState<TargetElementState>({\n element: null,\n timedOut: false\n });\n\n useEffect(() => {\n if (!enabled || !selector) {\n setState({ element: null, timedOut: false });\n return;\n }\n\n let cancelled = false;\n const startedAt = Date.now();\n\n const findTarget = () => {\n if (cancelled) {\n return;\n }\n\n const element = document.querySelector(selector);\n\n if (element instanceof HTMLElement) {\n setState({ element, timedOut: false });\n return;\n }\n\n if (Date.now() - startedAt >= timeoutMs) {\n setState({ element: null, timedOut: true });\n return;\n }\n\n window.setTimeout(findTarget, 100);\n };\n\n setState({ element: null, timedOut: false });\n findTarget();\n\n return () => {\n cancelled = true;\n };\n }, [enabled, selector, timeoutMs]);\n\n return state;\n}\n","import {\r\n FloatingPortal,\r\n autoUpdate,\r\n offset,\r\n useFloating\r\n} from \"@floating-ui/react\";\r\nimport { useEffect } from \"react\";\r\nimport type { SunboardHotspot } from \"@sunboard/core\";\r\nimport { useInterpolated } from \"../hooks/useInterpolated\";\r\nimport { useSunboard } from \"../hooks/useSunboard\";\r\nimport { useTargetElement } from \"../hooks/useTargetElement\";\r\n\r\ntype HotspotProps = {\r\n hotspot: SunboardHotspot;\r\n hotspotKey: string;\r\n};\r\n\r\nconst HOTSPOT_RADIUS_PX = 9;\r\n\r\nexport function SunboardHotspots() {\r\n const { visibleHotspots } = useSunboard();\r\n\r\n return (\r\n <>\r\n {visibleHotspots.map(({ key, hotspot }) => (\r\n <Hotspot hotspot={hotspot} hotspotKey={key} key={key} />\r\n ))}\r\n </>\r\n );\r\n}\r\n\r\nfunction Hotspot({ hotspot, hotspotKey }: HotspotProps) {\r\n const { startTour } = useSunboard();\r\n const label = useInterpolated(hotspot.label);\r\n const target = useTargetElement(hotspot.target, true);\r\n const { refs, floatingStyles } = useFloating({\r\n placement: hotspot.placement,\r\n strategy: \"fixed\",\r\n middleware: [offset(-HOTSPOT_RADIUS_PX)],\r\n whileElementsMounted: autoUpdate\r\n });\r\n\r\n useEffect(() => {\r\n if (!target.element) {\r\n return;\r\n }\r\n\r\n refs.setReference(target.element);\r\n }, [refs, target.element]);\r\n\r\n if (!target.element) {\r\n return null;\r\n }\r\n\r\n return (\r\n <FloatingPortal>\r\n <button\r\n aria-label={label ?? `Start ${hotspot.action.tour} tour`}\r\n className=\"sunboard-hotspot\"\r\n data-pulse={hotspot.pulse}\r\n data-sunboard-hotspot={hotspotKey}\r\n onClick={() => {\r\n void startTour(hotspot.action.tour);\r\n }}\r\n ref={refs.setFloating}\r\n style={floatingStyles}\r\n type=\"button\"\r\n >\r\n <span className=\"sunboard-hotspot-dot\" />\r\n </button>\r\n </FloatingPortal>\r\n );\r\n}\r\n","import {\r\n arrow,\r\n FloatingArrow,\r\n FloatingPortal,\r\n flip,\r\n offset,\r\n shift,\r\n useFloating\r\n} from \"@floating-ui/react\";\r\nimport { useEffect, useRef, useState } from \"react\";\r\nimport { routeMatches } from \"../adapters/routes\";\r\nimport { useInterpolated } from \"../hooks/useInterpolated\";\r\nimport { useSunboard } from \"../hooks/useSunboard\";\r\nimport { useTargetElement } from \"../hooks/useTargetElement\";\r\n\r\nexport function SunboardTour() {\r\n const {\r\n activeTour,\r\n advanceTour,\r\n dismissTour,\r\n mode,\r\n reportTourError,\r\n route,\r\n tourError\r\n } = useSunboard();\r\n const arrowRef = useRef<SVGSVGElement | null>(null);\r\n const [spotlightRect, setSpotlightRect] = useState<DOMRect | null>(null);\r\n const routeReady = routeMatches(activeTour?.step.route, route ?? \"/\");\r\n const target = useTargetElement(\r\n activeTour?.step.target ?? null,\r\n Boolean(activeTour) && routeReady,\r\n 1_000\r\n );\r\n const { context, refs, floatingStyles, update } = useFloating({\r\n placement: activeTour?.step.placement ?? \"bottom\",\r\n middleware: [\r\n offset(16),\r\n flip(),\r\n shift({ padding: 12 }),\r\n arrow({ element: arrowRef })\r\n ]\r\n });\r\n\r\n useEffect(() => {\r\n if (!activeTour) {\r\n reportTourError(null);\r\n return;\r\n }\r\n\r\n if (!routeReady) {\r\n return;\r\n }\r\n\r\n if (!target.timedOut) {\r\n return;\r\n }\r\n\r\n const error = {\r\n message: \"Sunboard could not find the tour target.\",\r\n route: activeTour.step.route,\r\n stepKey: activeTour.step.key,\r\n target: activeTour.step.target,\r\n tourKey: activeTour.key\r\n };\r\n\r\n if (mode === \"preview\") {\r\n reportTourError(error);\r\n return;\r\n }\r\n\r\n reportTourError(null);\r\n void dismissTour();\r\n }, [activeTour, dismissTour, mode, reportTourError, routeReady, target.timedOut]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n return;\r\n }\r\n\r\n reportTourError(null);\r\n refs.setReference(target.element);\r\n target.element.scrollIntoView({ block: \"center\", inline: \"center\" });\r\n void update();\r\n }, [activeTour, refs, reportTourError, target.element, update]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n setSpotlightRect(null);\r\n return;\r\n }\r\n\r\n const updateSpotlight = () => {\r\n setSpotlightRect(target.element?.getBoundingClientRect() ?? null);\r\n };\r\n\r\n updateSpotlight();\r\n window.addEventListener(\"resize\", updateSpotlight);\r\n window.addEventListener(\"scroll\", updateSpotlight, true);\r\n\r\n target.element.setAttribute(\"data-sunboard-tour-target\", \"true\");\r\n\r\n return () => {\r\n window.removeEventListener(\"resize\", updateSpotlight);\r\n window.removeEventListener(\"scroll\", updateSpotlight, true);\r\n target.element?.removeAttribute(\"data-sunboard-tour-target\");\r\n setSpotlightRect(null);\r\n };\r\n }, [activeTour, target.element]);\r\n\r\n useEffect(() => {\r\n if (!activeTour || !target.element) {\r\n return;\r\n }\r\n\r\n const advanceOnTargetClick = () => {\r\n window.setTimeout(() => {\r\n void advanceTour();\r\n }, 0);\r\n };\r\n\r\n target.element.addEventListener(\"click\", advanceOnTargetClick);\r\n\r\n return () => {\r\n target.element?.removeEventListener(\"click\", advanceOnTargetClick);\r\n };\r\n }, [activeTour, advanceTour, target.element]);\r\n\r\n const tourName = useInterpolated(activeTour?.name);\r\n const stepTitle = useInterpolated(activeTour?.step.title);\r\n const stepBody = useInterpolated(activeTour?.step.body);\r\n\r\n if (!activeTour) {\r\n return null;\r\n }\r\n\r\n if (tourError && mode === \"preview\") {\r\n return (\r\n <div className=\"sunboard-debug\" role=\"alert\">\r\n <strong>{tourError.message}</strong>\r\n <span>Tour: {tourError.tourKey}</span>\r\n <span>Step: {tourError.stepKey}</span>\r\n {tourError.route ? <span>Route: {tourError.route}</span> : null}\r\n {tourError.target ? <span>Target: {tourError.target}</span> : null}\r\n <button onClick={() => void dismissTour()} type=\"button\">\r\n Dismiss\r\n </button>\r\n </div>\r\n );\r\n }\r\n\r\n if (!routeReady || !target.element) {\r\n return null;\r\n }\r\n\r\n const isLastStep = activeTour.stepIndex === activeTour.totalSteps - 1;\r\n\r\n return (\r\n <FloatingPortal>\r\n <SunboardTourScrim rect={spotlightRect} />\r\n <section\r\n aria-label={`${tourName} tour step`}\r\n className=\"sunboard-tour\"\r\n ref={refs.setFloating}\r\n role=\"dialog\"\r\n style={floatingStyles}\r\n >\r\n <FloatingArrow\r\n className=\"sunboard-tour-arrow\"\r\n context={context}\r\n fill=\"var(--sunboard-tour-background)\"\r\n ref={arrowRef}\r\n stroke=\"var(--sunboard-tour-border)\"\r\n strokeWidth={1}\r\n tipRadius={2}\r\n />\r\n <div className=\"sunboard-tour-meta\">\r\n {activeTour.stepIndex + 1} / {activeTour.totalSteps}\r\n </div>\r\n <h2 className=\"sunboard-tour-title\">{stepTitle}</h2>\r\n {stepBody ? (\r\n <p className=\"sunboard-tour-body\">{stepBody}</p>\r\n ) : null}\r\n <div className=\"sunboard-tour-actions\">\r\n <button\r\n className=\"sunboard-tour-secondary\"\r\n onClick={() => void dismissTour()}\r\n type=\"button\"\r\n >\r\n Dismiss\r\n </button>\r\n <button\r\n className=\"sunboard-tour-primary\"\r\n onClick={() => void advanceTour()}\r\n type=\"button\"\r\n >\r\n {isLastStep ? \"Finish\" : \"Next\"}\r\n </button>\r\n </div>\r\n </section>\r\n </FloatingPortal>\r\n );\r\n}\r\n\r\nfunction SunboardTourScrim({ rect }: { rect: DOMRect | null }) {\r\n if (!rect) {\r\n return <div className=\"sunboard-tour-scrim\" />;\r\n }\r\n\r\n const padding = 8;\r\n const radius = 12;\r\n const left = Math.max(rect.left - padding, 0);\r\n const top = Math.max(rect.top - padding, 0);\r\n const width = rect.width + padding * 2;\r\n const height = rect.height + padding * 2;\r\n const maskId = \"sunboard-tour-spotlight-mask\";\r\n\r\n return (\r\n <svg\r\n aria-hidden=\"true\"\r\n className=\"sunboard-tour-scrim sunboard-tour-spotlight\"\r\n focusable=\"false\"\r\n >\r\n <defs>\r\n <mask id={maskId}>\r\n <rect fill=\"white\" height=\"100%\" width=\"100%\" x=\"0\" y=\"0\" />\r\n <rect\r\n fill=\"black\"\r\n height={height}\r\n rx={radius}\r\n ry={radius}\r\n width={width}\r\n x={left}\r\n y={top}\r\n />\r\n </mask>\r\n </defs>\r\n <rect\r\n fill=\"var(--sunboard-overlay-color)\"\r\n height=\"100%\"\r\n mask={`url(#${maskId})`}\r\n width=\"100%\"\r\n x=\"0\"\r\n y=\"0\"\r\n />\r\n </svg>\r\n );\r\n}\r\n","import { useEffect, useState } from \"react\";\r\nimport { useChecklist } from \"../hooks/useChecklist\";\r\nimport { ChecklistStep } from \"./ChecklistStep\";\r\nimport { SunboardHotspots } from \"./SunboardHotspots\";\r\nimport { SunboardTour } from \"./SunboardTour\";\r\n\r\nexport function SunboardChecklist() {\r\n const [open, setOpen] = useState(true);\r\n const {\r\n visible,\r\n title,\r\n subtitle,\r\n steps,\r\n completedCount,\r\n totalSteps,\r\n remainingCount,\r\n progress,\r\n isCompleted,\r\n startStep,\r\n completion,\r\n dismissCompletion\r\n } = useChecklist();\r\n\r\n // Auto-dismiss the completion screen after the spec-author-specified delay.\r\n // Lives in the widget rather than the hook so custom checklists can choose\r\n // their own timing UX (e.g. dismiss on tab change) without inheriting ours.\r\n useEffect(() => {\r\n if (!completion?.dismissAfterMs) return;\r\n const handle = window.setTimeout(dismissCompletion, completion.dismissAfterMs);\r\n return () => window.clearTimeout(handle);\r\n }, [completion, dismissCompletion]);\r\n\r\n if (!visible || !title) {\r\n return null;\r\n }\r\n\r\n if (completion) {\r\n return (\r\n <aside\r\n className=\"sunboard-root sunboard-root-completion\"\r\n aria-label={`${title} complete`}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n >\r\n <button\r\n className=\"sunboard-close sunboard-completion-close\"\r\n type=\"button\"\r\n onClick={dismissCompletion}\r\n aria-label=\"Dismiss completion message\"\r\n >\r\n x\r\n </button>\r\n <div className=\"sunboard-completion\">\r\n <div className=\"sunboard-completion-check\" aria-hidden=\"true\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"3\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polyline points=\"5 12 10 17 19 8\" />\r\n </svg>\r\n </div>\r\n {completion.subtitle ? (\r\n <p className=\"sunboard-completion-subtitle\">{completion.subtitle}</p>\r\n ) : null}\r\n <h2 className=\"sunboard-completion-title\">{completion.title}</h2>\r\n {completion.message ? (\r\n <p className=\"sunboard-completion-message\">{completion.message}</p>\r\n ) : null}\r\n </div>\r\n </aside>\r\n );\r\n }\r\n\r\n if (!open) {\r\n return (\r\n <button\r\n className=\"sunboard-launcher\"\r\n type=\"button\"\r\n onClick={() => setOpen(true)}\r\n aria-label={`Open ${title} checklist, ${remainingCount} tasks remaining`}\r\n >\r\n <span className=\"sunboard-launcher-count\">{remainingCount}</span>\r\n </button>\r\n );\r\n }\r\n\r\n return (\r\n <aside className=\"sunboard-root\" aria-label={`${title} checklist`}>\r\n <div className=\"sunboard-header\">\r\n <div>\r\n {subtitle ? <p className=\"sunboard-eyebrow\">{subtitle}</p> : null}\r\n <h2 className=\"sunboard-title\">{title}</h2>\r\n </div>\r\n <div className=\"sunboard-header-actions\">\r\n <p\r\n className=\"sunboard-progress-count\"\r\n aria-label=\"Checklist progress\"\r\n >\r\n {completedCount} / {totalSteps}\r\n </p>\r\n <button\r\n className=\"sunboard-close\"\r\n type=\"button\"\r\n onClick={() => setOpen(false)}\r\n aria-label={`Close ${title} checklist`}\r\n >\r\n x\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div\r\n className=\"sunboard-progress\"\r\n role=\"progressbar\"\r\n aria-label={`${title} progress`}\r\n aria-valuemin={0}\r\n aria-valuemax={totalSteps}\r\n aria-valuenow={completedCount}\r\n >\r\n <div\r\n className=\"sunboard-progress-fill\"\r\n style={{ width: `${progress}%` }}\r\n />\r\n </div>\r\n\r\n <ol className=\"sunboard-step-list\">\r\n {steps.map((step) => (\r\n <ChecklistStep\r\n completed={isCompleted(step.key)}\r\n key={step.key}\r\n onStart={() => startStep(step)}\r\n step={step}\r\n />\r\n ))}\r\n </ol>\r\n </aside>\r\n );\r\n}\r\n\r\nexport const Sunboard = Object.assign(SunboardChecklist, {\r\n Checklist: SunboardChecklist,\r\n Hotspots: SunboardHotspots,\r\n Tour: SunboardTour\r\n});\r\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunboard/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React SDK for the Sunboard onboarding runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@floating-ui/react": "^0.27.19",
|
|
29
|
-
"@sunboard/core": "0.1.
|
|
29
|
+
"@sunboard/core": "0.1.2"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": ">=18.3.0 || >=19.0.0",
|