@pablo2410/shared-ui 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -208,4 +208,200 @@ interface UseSpotlightResult {
208
208
  */
209
209
  declare function useSpotlight(selector: string | null): UseSpotlightResult;
210
210
 
211
- export { type PanelPosition, type Placement, type Rect, type Size, type SpotlightFrame, type TourProgress, TourShell, type TourShellProps, type TourShellSkin, type TourSpotlightTarget, type TourStatus, type TourStep, type TourStepKind, type UseSpotlightResult, type UseTourOptions, type UseTourResult, computePanelPosition, computeSpotlightFrame, useSpotlight, useTour };
211
+ /**
212
+ * The tour registry + launcher store — the one place a module's tour
213
+ * definition and the "is a tour open right now" flag live, so the header's
214
+ * "Take the tour" trigger, the tour host, and the module's own page code
215
+ * never talk to each other directly.
216
+ *
217
+ * A module's whole integration is a definition object (see
218
+ * TourDefinition) passed to `useRegisterTour`, plus `data-tour-target`
219
+ * attributes on the elements its spotlight steps point at. Everything else
220
+ * — progress storage, the header trigger, the overlay, narration — is shared.
221
+ *
222
+ * Plain functions, no React import: testable in a Node environment (this
223
+ * package has no jsdom set up — see tour.test.ts), same split as
224
+ * tourMachine.ts. TourProvider.tsx is the React binding.
225
+ */
226
+
227
+ interface TourDefinition {
228
+ /** Stable, lowercase-kebab id, e.g. "policy-deployment". It is the key
229
+ * progress is stored under in Portal, so never rename a shipped tour's
230
+ * id — users' progress and "done" state would reset. */
231
+ id: string;
232
+ /** The steps, in order. A step that should highlight a live element sets
233
+ * `spotlight.selector` to the value of a `data-tour-target` attribute in
234
+ * the module's DOM. */
235
+ steps: TourStep[];
236
+ /** Open the tour by itself for a user who has never seen it or left it
237
+ * part-way (resuming at their last step). Off by default. Never fires
238
+ * when the user's progress couldn't be read, and never for a tour they
239
+ * finished or dismissed — those only reopen from "Take the tour". */
240
+ autoStart?: boolean;
241
+ }
242
+ declare class InvalidTourDefinitionError extends Error {
243
+ readonly problems: string[];
244
+ constructor(tourId: string, problems: string[]);
245
+ }
246
+ /** Returns a list of problems; empty means the definition is usable. */
247
+ declare function validateTourDefinition(def: TourDefinition): string[];
248
+ interface TourSession {
249
+ /** True = start at step 1 regardless of saved progress (the header's
250
+ * "Take the tour" replay). False = resume from the saved step. */
251
+ restart: boolean;
252
+ }
253
+ interface TourStoreState {
254
+ /** The tour the header trigger and host act on: the most recently
255
+ * registered one still mounted (a page-level tour wins over a
256
+ * module-level one while its page is open). */
257
+ active: TourDefinition | null;
258
+ /** Non-null while the tour overlay is open. */
259
+ session: TourSession | null;
260
+ }
261
+ interface TourStore {
262
+ /** Registers (or replaces, by id) a tour. Throws InvalidTourDefinitionError
263
+ * for an unusable definition. Returns the unregister function. */
264
+ register(def: TourDefinition): () => void;
265
+ /** Opens the active tour. No-op when none is registered. */
266
+ open(session?: TourSession): void;
267
+ close(): void;
268
+ getState(): TourStoreState;
269
+ subscribe(listener: () => void): () => void;
270
+ }
271
+ declare function createTourStore(): TourStore;
272
+ /** The store modules share by default. `TourProvider` can swap in another
273
+ * (tests, or an app that wants isolation). */
274
+ declare const defaultTourStore: TourStore;
275
+
276
+ /** The id Portal's existing, tour-id-less state belongs to. */
277
+ declare const SERVICE_HUB_TOUR_ID = "service-hub";
278
+ interface TourProgressUpdate {
279
+ status: Exclude<TourStatus, "unseen">;
280
+ lastStepId: string | null;
281
+ }
282
+ interface TourProgressTransport {
283
+ read(tourId: string): Promise<TourProgress>;
284
+ write(tourId: string, update: TourProgressUpdate): Promise<void>;
285
+ }
286
+ declare class TourProgressError extends Error {
287
+ readonly status?: number;
288
+ constructor(message: string, status?: number);
289
+ }
290
+ interface PortalTransportOptions {
291
+ /** Portal origin. Defaults to the platform Portal (`localhost:3000` on the
292
+ * local sandbox) — see services/platformDomain. */
293
+ baseUrl?: string;
294
+ fetchImpl?: typeof fetch;
295
+ }
296
+ declare function createPortalTourProgressTransport(opts?: PortalTransportOptions): TourProgressTransport;
297
+ interface TourProgressSnapshot {
298
+ /** "loading" until the first read settles. A failed read is "error" with
299
+ * `progress` falling back to unseen, so the tour is still usable. */
300
+ phase: "loading" | "ready" | "error";
301
+ progress: TourProgress;
302
+ error: Error | null;
303
+ }
304
+ interface TourProgressController {
305
+ getSnapshot(): TourProgressSnapshot;
306
+ subscribe(listener: () => void): () => void;
307
+ load(): Promise<void>;
308
+ /** Updates local state at once, then persists. Writes go out in the order
309
+ * they were recorded, so rapid Next clicks can't land reversed. A failed
310
+ * write never throws — the tour must not block on storage. */
311
+ record(update: TourProgressUpdate): Promise<void>;
312
+ }
313
+ declare function createTourProgressController(transport: TourProgressTransport, tourId: string): TourProgressController;
314
+ /** Whether to open the tour on its own when the module loads: only for a
315
+ * user who has never seen it or left it part-way. Done and dismissed tours
316
+ * only reopen from the header's "Take the tour". */
317
+ declare function shouldAutoOpen(status: TourStatus): boolean;
318
+ /** The full auto-open decision, made once when the first read settles.
319
+ * A failed read ("error") never auto-opens: its fallback "unseen" is not
320
+ * real, and opening on every page load for progress that can't be saved
321
+ * would nag. */
322
+ declare function decideAutoOpen(autoStart: boolean | undefined, snapshot: Pick<TourProgressSnapshot, "phase" | "progress">): boolean;
323
+
324
+ /** Reserved `service` value that makes Portal use the onboarding persona. */
325
+ declare const ONBOARDING_NARRATION_SERVICE = "onboarding";
326
+ declare const NARRATION_PROMPT = "Narrate this onboarding step for me in 2-3 sentences.";
327
+ interface NarrationRequestInput {
328
+ service: typeof ONBOARDING_NARRATION_SERVICE;
329
+ insights: {
330
+ hook: string;
331
+ highlights?: string[];
332
+ features?: {
333
+ name: string;
334
+ detail: string;
335
+ }[];
336
+ };
337
+ messages: {
338
+ role: "user";
339
+ content: string;
340
+ }[];
341
+ }
342
+ declare function buildNarrationInput(step: TourStep): NarrationRequestInput;
343
+ /** Resolves with Opi's narration for the step, or rejects. */
344
+ type TourNarrator = (step: TourStep) => Promise<string>;
345
+ interface PortalNarratorOptions {
346
+ baseUrl?: string;
347
+ fetchImpl?: typeof fetch;
348
+ }
349
+ declare function createPortalNarrator(opts?: PortalNarratorOptions): TourNarrator;
350
+
351
+ interface TourProviderProps {
352
+ store?: TourStore;
353
+ transport?: TourProgressTransport;
354
+ narrator?: TourNarrator;
355
+ children: ReactNode;
356
+ }
357
+ declare function TourProvider({ store, transport, narrator, children, }: TourProviderProps): React.JSX.Element;
358
+ /**
359
+ * Registers the module's tour for as long as the calling component is
360
+ * mounted. That is all a module does to get the header's "Take the tour"
361
+ * trigger, the overlay, saved progress and narration.
362
+ *
363
+ * Pass a definition that is stable across renders (module scope, or
364
+ * useMemo) — a new object every render re-registers every render. Pass
365
+ * null/undefined to register nothing (e.g. while data is loading). An
366
+ * invalid definition is logged and ignored rather than thrown: a broken
367
+ * tour must never take down the page it sits on.
368
+ */
369
+ declare function useRegisterTour(def: TourDefinition | null | undefined): void;
370
+ declare function useTourState(): TourStoreState;
371
+ /** The tour the header trigger would open now, or null when the current
372
+ * module has registered none. */
373
+ declare function useActiveTour(): TourDefinition | null;
374
+ /** Imperative open/close for the active tour — what the header trigger uses. */
375
+ declare function useTourLauncher(): {
376
+ /** Opens from step 1, regardless of saved progress. */
377
+ start: () => void;
378
+ /** Opens with an explicit session (e.g. resume from saved progress). */
379
+ open: (session: TourSession) => void;
380
+ close: () => void;
381
+ available: boolean;
382
+ };
383
+ interface UseTourProgressResult extends TourProgressSnapshot {
384
+ record: (update: TourProgressUpdate) => Promise<void>;
385
+ }
386
+ /** The user's saved progress through one tour, read from and written to
387
+ * Portal (see tourProgress.ts). */
388
+ declare function useTourProgress(tourId: string): UseTourProgressResult;
389
+ /** The narrator the tour host uses — exposed so a module's own tour UI can
390
+ * narrate in the same voice. */
391
+ declare function useTourNarrator(): TourNarrator;
392
+
393
+ interface TakeTheTourButtonProps {
394
+ /** Defaults to "Take the tour". */
395
+ label?: string;
396
+ className?: string;
397
+ }
398
+ declare function TakeTheTourButton({ label, className, }: TakeTheTourButtonProps): React.JSX.Element | null;
399
+
400
+ interface OpiTourHostProps {
401
+ /** Orb/avatar shown in the tour header. Defaults to a plain mark. */
402
+ orb?: ReactNode;
403
+ skin?: TourShellSkin;
404
+ }
405
+ declare function OpiTourHost(props: OpiTourHostProps): React.JSX.Element | null;
406
+
407
+ export { InvalidTourDefinitionError, NARRATION_PROMPT, type NarrationRequestInput, ONBOARDING_NARRATION_SERVICE, OpiTourHost, type OpiTourHostProps, type PanelPosition, type Placement, type PortalNarratorOptions, type PortalTransportOptions, type Rect, SERVICE_HUB_TOUR_ID, type Size, type SpotlightFrame, TakeTheTourButton, type TakeTheTourButtonProps, type TourDefinition, type TourNarrator, type TourProgress, type TourProgressController, TourProgressError, type TourProgressSnapshot, type TourProgressTransport, type TourProgressUpdate, TourProvider, type TourProviderProps, type TourSession, TourShell, type TourShellProps, type TourShellSkin, type TourSpotlightTarget, type TourStatus, type TourStep, type TourStepKind, type TourStore, type TourStoreState, type UseSpotlightResult, type UseTourOptions, type UseTourProgressResult, type UseTourResult, buildNarrationInput, computePanelPosition, computeSpotlightFrame, createPortalNarrator, createPortalTourProgressTransport, createTourProgressController, createTourStore, decideAutoOpen, defaultTourStore, shouldAutoOpen, useActiveTour, useRegisterTour, useSpotlight, useTour, useTourLauncher, useTourNarrator, useTourProgress, useTourState, validateTourDefinition };