@sunboard/react 0.5.0 → 0.6.1
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 +97 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +323 -18
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +85 -0
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import { RuntimeBootstrapRequest, RuntimeBootstrapResponse, RuntimeExperience, RuntimeProgress, RuntimeTrackRequest, RuntimeTrackResponse, SunboardRuntimeApiError, SunboardRuntimeClient, SunboardRuntimeClientOptions } from "@sunboard/core/runtime-api";
|
|
3
|
-
import * as
|
|
4
|
-
import { NormalizedSunboardSpec, SunboardHotspot, SunboardStep, SunboardTourStep, SurveyQuestionType, TrackEventName } from "@sunboard/core";
|
|
2
|
+
import { RuntimeBootstrapRequest, RuntimeBootstrapResponse, RuntimeExperience, RuntimeProgress, RuntimeTrackRequest, RuntimeTrackResponse, SunboardRuntimeApiError, SunboardRuntimeClient, SunboardRuntimeClientOptions, TooltipDismissVia } from "@sunboard/core/runtime-api";
|
|
3
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
|
+
import { NormalizedSunboardSpec, SunboardHotspot, SunboardPlacement, SunboardStep, SunboardTooltip, SunboardTourStep, SurveyQuestionType, TrackEventName } from "@sunboard/core";
|
|
5
5
|
|
|
6
6
|
//#region src/adapters/navigation.d.ts
|
|
7
7
|
type NavigateCallback = (url: string) => void | Promise<void>;
|
|
@@ -52,6 +52,23 @@ type TourResult = {
|
|
|
52
52
|
ok: false;
|
|
53
53
|
reason: "not-ready" | "missing-user" | "missing-tour";
|
|
54
54
|
};
|
|
55
|
+
type TooltipResult = {
|
|
56
|
+
ok: true;
|
|
57
|
+
} | {
|
|
58
|
+
ok: false;
|
|
59
|
+
reason: "not-ready" | "missing-user" | "missing-tooltip";
|
|
60
|
+
};
|
|
61
|
+
type VisibleSunboardTooltip = {
|
|
62
|
+
key: string;
|
|
63
|
+
tooltip: SunboardTooltip;
|
|
64
|
+
/**
|
|
65
|
+
* True when the user asked for this tooltip (a checklist step's
|
|
66
|
+
* `openTooltip` action), false when it is showing proactively. A requested
|
|
67
|
+
* tooltip shows even if it was dismissed before — the user explicitly asked
|
|
68
|
+
* to be shown where the action happens.
|
|
69
|
+
*/
|
|
70
|
+
requested: boolean;
|
|
71
|
+
};
|
|
55
72
|
type ActiveSunboardTour = {
|
|
56
73
|
key: string;
|
|
57
74
|
name: string;
|
|
@@ -88,11 +105,33 @@ type SunboardContextValue = {
|
|
|
88
105
|
}) => Promise<TourResult>;
|
|
89
106
|
advanceTour: () => Promise<TourResult>;
|
|
90
107
|
navigateToStep: (step: SunboardStep) => Promise<void>;
|
|
91
|
-
startChecklistStep: (step: SunboardStep) => Promise<TourResult | void>;
|
|
108
|
+
startChecklistStep: (step: SunboardStep) => Promise<TourResult | TooltipResult | void>;
|
|
92
109
|
visibleHotspots: Array<{
|
|
93
110
|
key: string;
|
|
94
111
|
hotspot: SunboardHotspot;
|
|
95
112
|
}>;
|
|
113
|
+
dismissedTooltipKeys: ReadonlySet<string>;
|
|
114
|
+
/**
|
|
115
|
+
* Tooltips that qualify for the current route, requested-first. Renderers
|
|
116
|
+
* show ONE at a time: the first entry whose target resolves.
|
|
117
|
+
*/
|
|
118
|
+
visibleTooltips: VisibleSunboardTooltip[];
|
|
119
|
+
/**
|
|
120
|
+
* Open a tooltip on demand (the checklist's openTooltip action). Navigates
|
|
121
|
+
* are the caller's job; this just marks the tooltip requested so it renders
|
|
122
|
+
* once its route matches and its target is present, dismissal or not.
|
|
123
|
+
*/
|
|
124
|
+
openTooltip: (tooltipKey: string) => Promise<TooltipResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Never show this tooltip again. `via: "close"` is the negative signal (the
|
|
127
|
+
* default); `via: "action"` records that the user took the tooltip's action;
|
|
128
|
+
* `via: "target"` records that the user clicked the tooltip's target element.
|
|
129
|
+
*/
|
|
130
|
+
dismissTooltip: (tooltipKey: string, options?: {
|
|
131
|
+
via?: TooltipDismissVia;
|
|
132
|
+
}) => Promise<TooltipResult>;
|
|
133
|
+
/** Report that a tooltip actually reached the user's eyes (deduped per session). */
|
|
134
|
+
markTooltipSeen: (tooltipKey: string) => void;
|
|
96
135
|
};
|
|
97
136
|
//#endregion
|
|
98
137
|
//#region src/components/SunboardProvider.d.ts
|
|
@@ -132,21 +171,31 @@ declare function SunboardProvider({
|
|
|
132
171
|
identities: identitiesProp,
|
|
133
172
|
onTrack,
|
|
134
173
|
children
|
|
135
|
-
}: SunboardProviderProps):
|
|
174
|
+
}: SunboardProviderProps): react_jsx_runtime0.JSX.Element;
|
|
136
175
|
//#endregion
|
|
137
176
|
//#region src/components/SunboardHotspots.d.ts
|
|
138
|
-
declare function SunboardHotspots():
|
|
177
|
+
declare function SunboardHotspots(): react_jsx_runtime0.JSX.Element;
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/components/SunboardTooltips.d.ts
|
|
180
|
+
/**
|
|
181
|
+
* Renders at most one tooltip: the first visible candidate whose target
|
|
182
|
+
* resolves. A candidate whose selector never appears is skipped for the rest
|
|
183
|
+
* of the session (without recording a dismissal — the user rejected nothing),
|
|
184
|
+
* so one stale selector can't block the tooltips behind it.
|
|
185
|
+
*/
|
|
186
|
+
declare function SunboardTooltips(): react_jsx_runtime0.JSX.Element | null;
|
|
139
187
|
//#endregion
|
|
140
188
|
//#region src/components/SunboardTour.d.ts
|
|
141
|
-
declare function SunboardTour():
|
|
189
|
+
declare function SunboardTour(): react_jsx_runtime0.JSX.Element | null;
|
|
142
190
|
//#endregion
|
|
143
191
|
//#region src/components/Sunboard.d.ts
|
|
144
|
-
declare function SunboardChecklist():
|
|
145
|
-
declare function SunboardSurvey():
|
|
192
|
+
declare function SunboardChecklist(): react_jsx_runtime0.JSX.Element | null;
|
|
193
|
+
declare function SunboardSurvey(): react_jsx_runtime0.JSX.Element | null;
|
|
146
194
|
declare const Sunboard: typeof SunboardChecklist & {
|
|
147
195
|
Checklist: typeof SunboardChecklist;
|
|
148
196
|
Survey: typeof SunboardSurvey;
|
|
149
197
|
Hotspots: typeof SunboardHotspots;
|
|
198
|
+
Tooltips: typeof SunboardTooltips;
|
|
150
199
|
Tour: typeof SunboardTour;
|
|
151
200
|
};
|
|
152
201
|
//#endregion
|
|
@@ -234,5 +283,43 @@ type UseSurveyResult = {
|
|
|
234
283
|
};
|
|
235
284
|
declare function useSurvey(): UseSurveyResult;
|
|
236
285
|
//#endregion
|
|
237
|
-
|
|
286
|
+
//#region src/hooks/useTooltips.d.ts
|
|
287
|
+
type TooltipView = {
|
|
288
|
+
key: string;
|
|
289
|
+
title: string;
|
|
290
|
+
body?: string;
|
|
291
|
+
/** CSS selector of the element the tooltip points at. */
|
|
292
|
+
target: string;
|
|
293
|
+
placement: SunboardPlacement;
|
|
294
|
+
/** True when a tour action is attached; `engage` starts it. */
|
|
295
|
+
hasAction: boolean;
|
|
296
|
+
actionLabel?: string;
|
|
297
|
+
/** True when the user asked for this tooltip via a checklist step. */
|
|
298
|
+
requested: boolean;
|
|
299
|
+
};
|
|
300
|
+
type UseTooltipsResult = {
|
|
301
|
+
/**
|
|
302
|
+
* Tooltips that qualify for the current route (undismissed, or explicitly
|
|
303
|
+
* requested). Render ONE at a time — the first whose target you can anchor.
|
|
304
|
+
*/
|
|
305
|
+
tooltips: TooltipView[];
|
|
306
|
+
/** Report that a tooltip is actually on screen (deduped per session). */
|
|
307
|
+
markSeen: (key: string) => void;
|
|
308
|
+
/** Close without acting — the tooltip never shows again. */
|
|
309
|
+
dismiss: (key: string) => void;
|
|
310
|
+
/** Take the tooltip's action: starts its tour and retires the tooltip. */
|
|
311
|
+
engage: (key: string) => void;
|
|
312
|
+
/**
|
|
313
|
+
* Report that the user clicked the tooltip's target element: the nudge
|
|
314
|
+
* worked, so this retires the tooltip and records the engagement.
|
|
315
|
+
*/
|
|
316
|
+
markTargetClicked: (key: string) => void;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Headless counterpart of `<SunboardTooltips>`: the same visibility, seen,
|
|
320
|
+
* dismissal, and engagement semantics with rendering left to the host.
|
|
321
|
+
*/
|
|
322
|
+
declare function useTooltips(): UseTooltipsResult;
|
|
323
|
+
//#endregion
|
|
324
|
+
export { type ChecklistViewStep, type RuntimeBootstrapRequest, type RuntimeBootstrapResponse, type RuntimeExperience, type RuntimeProgress, type RuntimeTrackRequest, type RuntimeTrackResponse, Sunboard, SunboardChecklist, type SunboardContextValue, SunboardHotspots, SunboardProvider, type SunboardProviderProps, SunboardRuntimeApiError, SunboardRuntimeClient, type SunboardRuntimeClientOptions, SunboardSurvey, SunboardTooltips, SunboardTour, type SunboardUser, type SurveyResult, type SurveyViewOption, type SurveyViewQuestion, type SurveyViewStep, type TooltipResult, type TooltipView, type TourResult, type TrackProperties, type TrackResult, type UseChecklistResult, type UseSurveyResult, type UseTooltipsResult, type VisibleSunboardTooltip, useChecklist, useSunboard, useSurvey, useTooltips };
|
|
238
325
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapters/navigation.ts","../src/lib/detect-identities.ts","../src/hooks/sunboard-context.ts","../src/components/SunboardProvider.tsx","../src/components/SunboardHotspots.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts","../src/hooks/useSurvey.ts"],"sourcesContent":[],"mappings":";;;;;;KAAY,gBAAA,2BAA2C;;;;;;;;;AAAvD;;;;ACkBA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapters/navigation.ts","../src/lib/detect-identities.ts","../src/hooks/sunboard-context.ts","../src/components/SunboardProvider.tsx","../src/components/SunboardHotspots.tsx","../src/components/SunboardTooltips.tsx","../src/components/SunboardTour.tsx","../src/components/Sunboard.tsx","../src/hooks/useSunboard.ts","../src/hooks/useChecklist.ts","../src/hooks/useSurvey.ts","../src/hooks/useTooltips.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -148,28 +148,32 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
148
148
|
}, [user, ownedAttributes]);
|
|
149
149
|
const [completedStepKeys, setCompletedStepKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
150
150
|
const [completedTourKeys, setCompletedTourKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
151
|
+
const [dismissedTooltipKeys, setDismissedTooltipKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
151
152
|
const [activeTourState, setActiveTourState] = useState(null);
|
|
153
|
+
const [requestedTooltipKey, setRequestedTooltipKey] = useState(null);
|
|
154
|
+
const seenTooltipKeys = useRef(/* @__PURE__ */ new Set());
|
|
152
155
|
const lastNavigatedTourStep = useRef(null);
|
|
153
156
|
const storageKey = !hostedMode && resolvedSpec && user ? completedToursStorageKey(resolvedSpec.key, user.id) : null;
|
|
157
|
+
const tooltipStorageKey = !hostedMode && resolvedSpec && user ? dismissedTooltipsStorageKey(resolvedSpec.key, user.id) : null;
|
|
154
158
|
const experienceKey = activeSurvey?.key ?? activeExperience?.key ?? resolvedSpec?.key ?? null;
|
|
155
159
|
const versionId = activeSurvey?.version.id ?? activeExperience?.version.id ?? null;
|
|
156
160
|
useEffect(() => {
|
|
157
161
|
setCompletedStepKeys(/* @__PURE__ */ new Set());
|
|
158
162
|
setActiveTourState(null);
|
|
163
|
+
setRequestedTooltipKey(null);
|
|
164
|
+
seenTooltipKeys.current = /* @__PURE__ */ new Set();
|
|
159
165
|
lastNavigatedTourStep.current = null;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
setCompletedTourKeys(readCompletedTours(storageKey));
|
|
166
|
+
setCompletedTourKeys(storageKey ? readStoredKeys(storageKey) : /* @__PURE__ */ new Set());
|
|
167
|
+
setDismissedTooltipKeys(tooltipStorageKey ? readStoredKeys(tooltipStorageKey) : /* @__PURE__ */ new Set());
|
|
165
168
|
}, [
|
|
166
169
|
resolvedSpec?.key,
|
|
167
170
|
storageKey,
|
|
171
|
+
tooltipStorageKey,
|
|
168
172
|
user?.id
|
|
169
173
|
]);
|
|
170
174
|
useEffect(() => {
|
|
171
175
|
if (!hostedMode || !activeExperience) return;
|
|
172
|
-
applyProgress(activeExperience.progress, setCompletedStepKeys, setCompletedTourKeys);
|
|
176
|
+
applyProgress(activeExperience.progress, setCompletedStepKeys, setCompletedTourKeys, setDismissedTooltipKeys);
|
|
173
177
|
}, [activeExperience, hostedMode]);
|
|
174
178
|
const effectiveCompletedStepKeys = useMemo(() => {
|
|
175
179
|
if (!hostedMode || !activeExperience) return completedStepKeys;
|
|
@@ -187,6 +191,14 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
187
191
|
completedTourKeys,
|
|
188
192
|
hostedMode
|
|
189
193
|
]);
|
|
194
|
+
const effectiveDismissedTooltipKeys = useMemo(() => {
|
|
195
|
+
if (!hostedMode || !activeExperience) return dismissedTooltipKeys;
|
|
196
|
+
return mergeKeys(dismissedTooltipKeys, activeExperience.progress.dismissedTooltipKeys);
|
|
197
|
+
}, [
|
|
198
|
+
activeExperience,
|
|
199
|
+
dismissedTooltipKeys,
|
|
200
|
+
hostedMode
|
|
201
|
+
]);
|
|
190
202
|
useEffect(() => {
|
|
191
203
|
if (!resolvedSpec) return;
|
|
192
204
|
const tourCompletedStepKeys = (resolvedSpec.checklist?.steps ?? []).filter((step) => step.completeWhen?.tour && effectiveCompletedTourKeys.has(step.completeWhen.tour)).map((step) => step.key);
|
|
@@ -243,7 +255,7 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
243
255
|
setCompletedTourKeys((current) => {
|
|
244
256
|
const next = new Set(current);
|
|
245
257
|
next.add(tourKey);
|
|
246
|
-
if (storageKey)
|
|
258
|
+
if (storageKey) writeStoredKeys(storageKey, next);
|
|
247
259
|
return next;
|
|
248
260
|
});
|
|
249
261
|
}, [storageKey]);
|
|
@@ -269,7 +281,7 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
269
281
|
user: toRuntimeUser(user),
|
|
270
282
|
versionId: versionId ?? void 0
|
|
271
283
|
});
|
|
272
|
-
if (response.progress) applyProgress(response.progress, setCompletedStepKeys, setCompletedTourKeys);
|
|
284
|
+
if (response.progress) applyProgress(response.progress, setCompletedStepKeys, setCompletedTourKeys, setDismissedTooltipKeys);
|
|
273
285
|
} catch {
|
|
274
286
|
networkOk = false;
|
|
275
287
|
}
|
|
@@ -423,7 +435,7 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
423
435
|
tourKey,
|
|
424
436
|
user: toRuntimeUser(user),
|
|
425
437
|
versionId: versionId ?? void 0
|
|
426
|
-
})).progress, setCompletedStepKeys, setCompletedTourKeys);
|
|
438
|
+
})).progress, setCompletedStepKeys, setCompletedTourKeys, setDismissedTooltipKeys);
|
|
427
439
|
} catch {}
|
|
428
440
|
}, [
|
|
429
441
|
client,
|
|
@@ -468,10 +480,106 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
468
480
|
resolvedSpec,
|
|
469
481
|
user
|
|
470
482
|
]);
|
|
483
|
+
const openTooltip = useCallback(async (tooltipKey) => {
|
|
484
|
+
if (resolvedLoading || !resolvedSpec) return {
|
|
485
|
+
ok: false,
|
|
486
|
+
reason: "not-ready"
|
|
487
|
+
};
|
|
488
|
+
if (!user) return {
|
|
489
|
+
ok: false,
|
|
490
|
+
reason: "missing-user"
|
|
491
|
+
};
|
|
492
|
+
if (!resolvedSpec.tooltips[tooltipKey]) return {
|
|
493
|
+
ok: false,
|
|
494
|
+
reason: "missing-tooltip"
|
|
495
|
+
};
|
|
496
|
+
setRequestedTooltipKey(tooltipKey);
|
|
497
|
+
return { ok: true };
|
|
498
|
+
}, [
|
|
499
|
+
resolvedLoading,
|
|
500
|
+
resolvedSpec,
|
|
501
|
+
user
|
|
502
|
+
]);
|
|
503
|
+
const dismissTooltip = useCallback(async (tooltipKey, options) => {
|
|
504
|
+
if (resolvedLoading || !resolvedSpec) return {
|
|
505
|
+
ok: false,
|
|
506
|
+
reason: "not-ready"
|
|
507
|
+
};
|
|
508
|
+
if (!user) return {
|
|
509
|
+
ok: false,
|
|
510
|
+
reason: "missing-user"
|
|
511
|
+
};
|
|
512
|
+
if (!resolvedSpec.tooltips[tooltipKey]) return {
|
|
513
|
+
ok: false,
|
|
514
|
+
reason: "missing-tooltip"
|
|
515
|
+
};
|
|
516
|
+
const via = options?.via ?? "close";
|
|
517
|
+
setRequestedTooltipKey((current) => current === tooltipKey ? null : current);
|
|
518
|
+
setDismissedTooltipKeys((current) => {
|
|
519
|
+
const next = mergeKeys(current, [tooltipKey]);
|
|
520
|
+
if (tooltipStorageKey && next !== current) writeStoredKeys(tooltipStorageKey, next);
|
|
521
|
+
return next;
|
|
522
|
+
});
|
|
523
|
+
if (hostedMode && client && experienceKey) client.dismissTooltip({
|
|
524
|
+
experienceKey,
|
|
525
|
+
origin: currentOrigin,
|
|
526
|
+
route: currentRoute,
|
|
527
|
+
tooltipKey,
|
|
528
|
+
user: toRuntimeUser(user),
|
|
529
|
+
versionId: versionId ?? void 0,
|
|
530
|
+
via
|
|
531
|
+
}).catch(() => {});
|
|
532
|
+
return { ok: true };
|
|
533
|
+
}, [
|
|
534
|
+
client,
|
|
535
|
+
currentOrigin,
|
|
536
|
+
currentRoute,
|
|
537
|
+
experienceKey,
|
|
538
|
+
hostedMode,
|
|
539
|
+
resolvedLoading,
|
|
540
|
+
resolvedSpec,
|
|
541
|
+
tooltipStorageKey,
|
|
542
|
+
user,
|
|
543
|
+
versionId
|
|
544
|
+
]);
|
|
545
|
+
const markTooltipSeen = useCallback((tooltipKey) => {
|
|
546
|
+
if (!resolvedSpec?.tooltips[tooltipKey] || seenTooltipKeys.current.has(tooltipKey)) return;
|
|
547
|
+
seenTooltipKeys.current.add(tooltipKey);
|
|
548
|
+
if (hostedMode && client && experienceKey && user) client.recordTooltipSeen({
|
|
549
|
+
experienceKey,
|
|
550
|
+
origin: currentOrigin,
|
|
551
|
+
route: currentRoute,
|
|
552
|
+
tooltipKey,
|
|
553
|
+
user: toRuntimeUser(user),
|
|
554
|
+
versionId: versionId ?? void 0
|
|
555
|
+
}).catch(() => {});
|
|
556
|
+
}, [
|
|
557
|
+
client,
|
|
558
|
+
currentOrigin,
|
|
559
|
+
currentRoute,
|
|
560
|
+
experienceKey,
|
|
561
|
+
hostedMode,
|
|
562
|
+
resolvedSpec,
|
|
563
|
+
user,
|
|
564
|
+
versionId
|
|
565
|
+
]);
|
|
471
566
|
const startChecklistStep = useCallback(async (step) => {
|
|
472
567
|
if (step.action?.type === "startTour") return startTour(step.action.tour);
|
|
568
|
+
if (step.action?.type === "openTooltip") {
|
|
569
|
+
const tooltipKey = step.action.tooltip;
|
|
570
|
+
const destination = resolvedSpec?.tooltips[tooltipKey]?.route ?? step.route;
|
|
571
|
+
if (destination && !routeMatches(destination, currentRoute)) await navigateWithFallback(destination, navigate);
|
|
572
|
+
return openTooltip(tooltipKey);
|
|
573
|
+
}
|
|
473
574
|
await navigateToStep(step);
|
|
474
|
-
}, [
|
|
575
|
+
}, [
|
|
576
|
+
currentRoute,
|
|
577
|
+
navigate,
|
|
578
|
+
navigateToStep,
|
|
579
|
+
openTooltip,
|
|
580
|
+
resolvedSpec,
|
|
581
|
+
startTour
|
|
582
|
+
]);
|
|
475
583
|
const visibleHotspots = useMemo(() => {
|
|
476
584
|
if (!resolvedSpec || activeTour) return [];
|
|
477
585
|
return Object.entries(resolvedSpec.hotspots).filter(([, hotspot]) => routeMatches(hotspot.route, currentRoute)).filter(([, hotspot]) => hotspot.repeatable || !effectiveCompletedTourKeys.has(hotspot.action.tour)).map(([key, hotspot]) => ({
|
|
@@ -484,6 +592,29 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
484
592
|
currentRoute,
|
|
485
593
|
resolvedSpec
|
|
486
594
|
]);
|
|
595
|
+
const visibleTooltips = useMemo(() => {
|
|
596
|
+
if (!resolvedSpec || activeTour) return [];
|
|
597
|
+
const requestedTooltip = requestedTooltipKey ? resolvedSpec.tooltips[requestedTooltipKey] : void 0;
|
|
598
|
+
if (requestedTooltipKey && requestedTooltip) {
|
|
599
|
+
if (!routeMatches(requestedTooltip.route, currentRoute)) return [];
|
|
600
|
+
return [{
|
|
601
|
+
key: requestedTooltipKey,
|
|
602
|
+
requested: true,
|
|
603
|
+
tooltip: requestedTooltip
|
|
604
|
+
}];
|
|
605
|
+
}
|
|
606
|
+
return Object.entries(resolvedSpec.tooltips).filter(([key, tooltip]) => routeMatches(tooltip.route, currentRoute) && !effectiveDismissedTooltipKeys.has(key)).map(([key, tooltip]) => ({
|
|
607
|
+
key,
|
|
608
|
+
requested: false,
|
|
609
|
+
tooltip
|
|
610
|
+
}));
|
|
611
|
+
}, [
|
|
612
|
+
activeTour,
|
|
613
|
+
currentRoute,
|
|
614
|
+
effectiveDismissedTooltipKeys,
|
|
615
|
+
requestedTooltipKey,
|
|
616
|
+
resolvedSpec
|
|
617
|
+
]);
|
|
487
618
|
const value = useMemo(() => ({
|
|
488
619
|
spec: resolvedSpec,
|
|
489
620
|
user: effectiveUser,
|
|
@@ -501,7 +632,12 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
501
632
|
advanceTour,
|
|
502
633
|
navigateToStep,
|
|
503
634
|
startChecklistStep,
|
|
504
|
-
visibleHotspots
|
|
635
|
+
visibleHotspots,
|
|
636
|
+
dismissedTooltipKeys: effectiveDismissedTooltipKeys,
|
|
637
|
+
visibleTooltips,
|
|
638
|
+
openTooltip,
|
|
639
|
+
dismissTooltip,
|
|
640
|
+
markTooltipSeen
|
|
505
641
|
}), [
|
|
506
642
|
resolvedSpec,
|
|
507
643
|
effectiveUser,
|
|
@@ -519,7 +655,12 @@ function SunboardProvider({ spec: specProp, user, loading: loadingProp, route, n
|
|
|
519
655
|
advanceTour,
|
|
520
656
|
navigateToStep,
|
|
521
657
|
startChecklistStep,
|
|
522
|
-
visibleHotspots
|
|
658
|
+
visibleHotspots,
|
|
659
|
+
effectiveDismissedTooltipKeys,
|
|
660
|
+
visibleTooltips,
|
|
661
|
+
openTooltip,
|
|
662
|
+
dismissTooltip,
|
|
663
|
+
markTooltipSeen
|
|
523
664
|
]);
|
|
524
665
|
return /* @__PURE__ */ jsx(SunboardContext.Provider, {
|
|
525
666
|
value,
|
|
@@ -639,9 +780,10 @@ function scheduleLateIdentityCapture(options) {
|
|
|
639
780
|
function hasUnsentIdentity(detected, sent) {
|
|
640
781
|
return Object.entries(detected).some(([provider, id]) => sent?.[provider] !== id);
|
|
641
782
|
}
|
|
642
|
-
function applyProgress(progress, setSteps, setTours) {
|
|
783
|
+
function applyProgress(progress, setSteps, setTours, setDismissedTooltips) {
|
|
643
784
|
setSteps((current) => mergeKeys(current, progress.completedStepKeys));
|
|
644
785
|
setTours((current) => mergeKeys(current, progress.completedTourKeys));
|
|
786
|
+
setDismissedTooltips?.((current) => mergeKeys(current, progress.dismissedTooltipKeys));
|
|
645
787
|
}
|
|
646
788
|
function mergeKeys(current, incoming) {
|
|
647
789
|
if (incoming.length === 0) return current;
|
|
@@ -665,6 +807,9 @@ function toRuntimeUser(user) {
|
|
|
665
807
|
function completedToursStorageKey(specKey, userId) {
|
|
666
808
|
return `sunboard:${specKey}:${userId}:completed-tours`;
|
|
667
809
|
}
|
|
810
|
+
function dismissedTooltipsStorageKey(specKey, userId) {
|
|
811
|
+
return `sunboard:${specKey}:${userId}:dismissed-tooltips`;
|
|
812
|
+
}
|
|
668
813
|
function getBrowserRoute() {
|
|
669
814
|
if (typeof window === "undefined") return "/";
|
|
670
815
|
return `${window.location.pathname}${window.location.search}`;
|
|
@@ -673,7 +818,7 @@ function getBrowserOrigin() {
|
|
|
673
818
|
if (typeof window === "undefined") return;
|
|
674
819
|
return window.location.origin;
|
|
675
820
|
}
|
|
676
|
-
function
|
|
821
|
+
function readStoredKeys(storageKey) {
|
|
677
822
|
if (typeof window === "undefined") return /* @__PURE__ */ new Set();
|
|
678
823
|
try {
|
|
679
824
|
const rawValue = window.localStorage.getItem(storageKey);
|
|
@@ -684,10 +829,10 @@ function readCompletedTours(storageKey) {
|
|
|
684
829
|
return /* @__PURE__ */ new Set();
|
|
685
830
|
}
|
|
686
831
|
}
|
|
687
|
-
function
|
|
832
|
+
function writeStoredKeys(storageKey, keys) {
|
|
688
833
|
if (typeof window === "undefined") return;
|
|
689
834
|
try {
|
|
690
|
-
window.localStorage.setItem(storageKey, JSON.stringify([...
|
|
835
|
+
window.localStorage.setItem(storageKey, JSON.stringify([...keys].sort()));
|
|
691
836
|
} catch {}
|
|
692
837
|
}
|
|
693
838
|
|
|
@@ -740,7 +885,8 @@ function useSunboard() {
|
|
|
740
885
|
//#region src/hooks/useChecklist.ts
|
|
741
886
|
function actionLabelFor(step) {
|
|
742
887
|
if (step.action?.type === "startTour") return "Start";
|
|
743
|
-
if (step.action
|
|
888
|
+
if (step.action?.type === "openTooltip") return "Show me";
|
|
889
|
+
if (step.route) return "Open";
|
|
744
890
|
}
|
|
745
891
|
function interpolateOptional$1(text, user) {
|
|
746
892
|
if (!text) return void 0;
|
|
@@ -1115,6 +1261,126 @@ function Hotspot({ hotspot, hotspotKey }) {
|
|
|
1115
1261
|
}) });
|
|
1116
1262
|
}
|
|
1117
1263
|
|
|
1264
|
+
//#endregion
|
|
1265
|
+
//#region src/components/SunboardTooltips.tsx
|
|
1266
|
+
/**
|
|
1267
|
+
* Renders at most one tooltip: the first visible candidate whose target
|
|
1268
|
+
* resolves. A candidate whose selector never appears is skipped for the rest
|
|
1269
|
+
* of the session (without recording a dismissal — the user rejected nothing),
|
|
1270
|
+
* so one stale selector can't block the tooltips behind it.
|
|
1271
|
+
*/
|
|
1272
|
+
function SunboardTooltips() {
|
|
1273
|
+
const { visibleTooltips } = useSunboard();
|
|
1274
|
+
const [skippedKeys, setSkippedKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
1275
|
+
const active = visibleTooltips.find(({ key }) => !skippedKeys.has(key)) ?? null;
|
|
1276
|
+
if (!active) return null;
|
|
1277
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
1278
|
+
onTargetMissing: () => setSkippedKeys((current) => new Set(current).add(active.key)),
|
|
1279
|
+
requested: active.requested,
|
|
1280
|
+
tooltip: active.tooltip,
|
|
1281
|
+
tooltipKey: active.key
|
|
1282
|
+
}, active.key);
|
|
1283
|
+
}
|
|
1284
|
+
function Tooltip({ tooltip, tooltipKey, requested, onTargetMissing }) {
|
|
1285
|
+
const { dismissTooltip, markTooltipSeen, startTour } = useSunboard();
|
|
1286
|
+
const arrowRef = useRef(null);
|
|
1287
|
+
const title = useInterpolated(tooltip.title);
|
|
1288
|
+
const body = useInterpolated(tooltip.body);
|
|
1289
|
+
const actionLabel = useInterpolated(tooltip.actionLabel) ?? "Show me how";
|
|
1290
|
+
const target = useTargetElement(tooltip.target, true);
|
|
1291
|
+
const { context, refs, floatingStyles, update } = useFloating({
|
|
1292
|
+
placement: tooltip.placement,
|
|
1293
|
+
middleware: [
|
|
1294
|
+
offset(12),
|
|
1295
|
+
flip(),
|
|
1296
|
+
shift({ padding: 12 }),
|
|
1297
|
+
arrow({ element: arrowRef })
|
|
1298
|
+
],
|
|
1299
|
+
whileElementsMounted: autoUpdate
|
|
1300
|
+
});
|
|
1301
|
+
useEffect(() => {
|
|
1302
|
+
if (!target.timedOut) return;
|
|
1303
|
+
onTargetMissing();
|
|
1304
|
+
}, [target.timedOut]);
|
|
1305
|
+
useEffect(() => {
|
|
1306
|
+
if (!target.element) return;
|
|
1307
|
+
refs.setReference(target.element);
|
|
1308
|
+
update();
|
|
1309
|
+
markTooltipSeen(tooltipKey);
|
|
1310
|
+
}, [
|
|
1311
|
+
markTooltipSeen,
|
|
1312
|
+
refs,
|
|
1313
|
+
target.element,
|
|
1314
|
+
tooltipKey,
|
|
1315
|
+
update
|
|
1316
|
+
]);
|
|
1317
|
+
useEffect(() => {
|
|
1318
|
+
const element = target.element;
|
|
1319
|
+
if (!element) return;
|
|
1320
|
+
const dismissOnTargetClick = () => {
|
|
1321
|
+
window.setTimeout(() => {
|
|
1322
|
+
dismissTooltip(tooltipKey, { via: "target" });
|
|
1323
|
+
}, 0);
|
|
1324
|
+
};
|
|
1325
|
+
element.addEventListener("click", dismissOnTargetClick);
|
|
1326
|
+
return () => {
|
|
1327
|
+
element.removeEventListener("click", dismissOnTargetClick);
|
|
1328
|
+
};
|
|
1329
|
+
}, [
|
|
1330
|
+
dismissTooltip,
|
|
1331
|
+
target.element,
|
|
1332
|
+
tooltipKey
|
|
1333
|
+
]);
|
|
1334
|
+
if (!target.element) return null;
|
|
1335
|
+
return /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsxs("section", {
|
|
1336
|
+
"aria-label": title,
|
|
1337
|
+
className: "sunboard-tooltip",
|
|
1338
|
+
"data-sunboard-tooltip": tooltipKey,
|
|
1339
|
+
"data-requested": requested,
|
|
1340
|
+
ref: refs.setFloating,
|
|
1341
|
+
role: "dialog",
|
|
1342
|
+
style: floatingStyles,
|
|
1343
|
+
children: [
|
|
1344
|
+
/* @__PURE__ */ jsx(FloatingArrow, {
|
|
1345
|
+
className: "sunboard-tooltip-arrow",
|
|
1346
|
+
context,
|
|
1347
|
+
fill: "var(--sunboard-tour-background)",
|
|
1348
|
+
ref: arrowRef,
|
|
1349
|
+
stroke: "var(--sunboard-tour-border)",
|
|
1350
|
+
strokeWidth: 1,
|
|
1351
|
+
tipRadius: 2
|
|
1352
|
+
}),
|
|
1353
|
+
/* @__PURE__ */ jsx("button", {
|
|
1354
|
+
"aria-label": `Dismiss ${title}`,
|
|
1355
|
+
className: "sunboard-tooltip-close",
|
|
1356
|
+
onClick: () => void dismissTooltip(tooltipKey),
|
|
1357
|
+
type: "button",
|
|
1358
|
+
children: "x"
|
|
1359
|
+
}),
|
|
1360
|
+
/* @__PURE__ */ jsx("h2", {
|
|
1361
|
+
className: "sunboard-tooltip-title",
|
|
1362
|
+
children: title
|
|
1363
|
+
}),
|
|
1364
|
+
body ? /* @__PURE__ */ jsx("p", {
|
|
1365
|
+
className: "sunboard-tooltip-body",
|
|
1366
|
+
children: body
|
|
1367
|
+
}) : null,
|
|
1368
|
+
tooltip.action ? /* @__PURE__ */ jsx("div", {
|
|
1369
|
+
className: "sunboard-tooltip-actions",
|
|
1370
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
1371
|
+
className: "sunboard-tooltip-action",
|
|
1372
|
+
onClick: () => {
|
|
1373
|
+
dismissTooltip(tooltipKey, { via: "action" });
|
|
1374
|
+
startTour(tooltip.action.tour);
|
|
1375
|
+
},
|
|
1376
|
+
type: "button",
|
|
1377
|
+
children: actionLabel
|
|
1378
|
+
})
|
|
1379
|
+
}) : null
|
|
1380
|
+
]
|
|
1381
|
+
}) });
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1118
1384
|
//#endregion
|
|
1119
1385
|
//#region src/components/SunboardTour.tsx
|
|
1120
1386
|
function SunboardTour() {
|
|
@@ -1524,9 +1790,48 @@ const Sunboard = Object.assign(SunboardChecklist, {
|
|
|
1524
1790
|
Checklist: SunboardChecklist,
|
|
1525
1791
|
Survey: SunboardSurvey,
|
|
1526
1792
|
Hotspots: SunboardHotspots,
|
|
1793
|
+
Tooltips: SunboardTooltips,
|
|
1527
1794
|
Tour: SunboardTour
|
|
1528
1795
|
});
|
|
1529
1796
|
|
|
1530
1797
|
//#endregion
|
|
1531
|
-
|
|
1798
|
+
//#region src/hooks/useTooltips.ts
|
|
1799
|
+
/**
|
|
1800
|
+
* Headless counterpart of `<SunboardTooltips>`: the same visibility, seen,
|
|
1801
|
+
* dismissal, and engagement semantics with rendering left to the host.
|
|
1802
|
+
*/
|
|
1803
|
+
function useTooltips() {
|
|
1804
|
+
const { user, visibleTooltips, markTooltipSeen, dismissTooltip, startTour } = useSunboard();
|
|
1805
|
+
return {
|
|
1806
|
+
tooltips: useMemo(() => visibleTooltips.map(({ key, tooltip, requested }) => ({
|
|
1807
|
+
key,
|
|
1808
|
+
title: interpolateTokens(tooltip.title, user ?? null),
|
|
1809
|
+
body: tooltip.body ? interpolateTokens(tooltip.body, user ?? null) : void 0,
|
|
1810
|
+
target: tooltip.target,
|
|
1811
|
+
placement: tooltip.placement,
|
|
1812
|
+
hasAction: Boolean(tooltip.action),
|
|
1813
|
+
actionLabel: tooltip.actionLabel ? interpolateTokens(tooltip.actionLabel, user ?? null) : void 0,
|
|
1814
|
+
requested
|
|
1815
|
+
})), [user, visibleTooltips]),
|
|
1816
|
+
markSeen: markTooltipSeen,
|
|
1817
|
+
dismiss: (key) => {
|
|
1818
|
+
dismissTooltip(key);
|
|
1819
|
+
},
|
|
1820
|
+
engage: useCallback((key) => {
|
|
1821
|
+
const entry = visibleTooltips.find((candidate) => candidate.key === key);
|
|
1822
|
+
dismissTooltip(key, { via: "action" });
|
|
1823
|
+
if (entry?.tooltip.action) startTour(entry.tooltip.action.tour);
|
|
1824
|
+
}, [
|
|
1825
|
+
dismissTooltip,
|
|
1826
|
+
startTour,
|
|
1827
|
+
visibleTooltips
|
|
1828
|
+
]),
|
|
1829
|
+
markTargetClicked: (key) => {
|
|
1830
|
+
dismissTooltip(key, { via: "target" });
|
|
1831
|
+
}
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
//#endregion
|
|
1836
|
+
export { Sunboard, SunboardChecklist, SunboardHotspots, SunboardProvider, SunboardRuntimeApiError, SunboardRuntimeClient, SunboardSurvey, SunboardTooltips, SunboardTour, useChecklist, useSunboard, useSurvey, useTooltips };
|
|
1532
1837
|
//# sourceMappingURL=index.mjs.map
|