@retoo/borda 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/borda.umd.js CHANGED
@@ -5384,6 +5384,8 @@ createHTML: (html) => {
5384
5384
  BordaEvent["ON_TOUR_NEXT"] = "tour:next";
5385
5385
  /** Fired when navigating to the previous step. */
5386
5386
  BordaEvent["ON_TOUR_PREV"] = "tour:prev";
5387
+ /** Fired when a step's target fails to resolve to a DOM element, just before the tour closes. */
5388
+ BordaEvent["ON_TOUR_ERROR"] = "tour:error";
5387
5389
  /** Fired when the ArrowRight key is pressed during an active tour. */
5388
5390
  BordaEvent["ON_KEYBOARD_NEXT"] = "keyboard:next";
5389
5391
  /** Fired when the ArrowLeft key is pressed during an active tour. */
@@ -6186,6 +6188,14 @@ createHTML: (html) => {
6186
6188
  }
6187
6189
  //#endregion
6188
6190
  //#region src/entities/step/model/lib/resolveBordaStepTarget.ts
6191
+ /** Runs `querySelector`, treating a malformed selector as "no match" instead of throwing. */
6192
+ function queryTarget(selector) {
6193
+ try {
6194
+ return document.querySelector(selector);
6195
+ } catch {
6196
+ return null;
6197
+ }
6198
+ }
6189
6199
  function buildSelector(query) {
6190
6200
  const parts = [];
6191
6201
  if (query.id) parts.push(`#${CSS.escape(query.id)}`);
@@ -6209,10 +6219,10 @@ createHTML: (html) => {
6209
6219
  function resolveBordaStepTarget(target) {
6210
6220
  if (!target) return null;
6211
6221
  if (target instanceof HTMLElement) return target;
6212
- if (typeof target === "string") return document.querySelector(target);
6222
+ if (typeof target === "string") return queryTarget(target);
6213
6223
  const selector = buildSelector(target);
6214
6224
  if (!selector) return null;
6215
- return document.querySelector(selector);
6225
+ return queryTarget(selector);
6216
6226
  }
6217
6227
  //#endregion
6218
6228
  //#region src/app/entrypoint/modules/borda-controller/lib/useBordaController.svelte.ts
@@ -6231,6 +6241,23 @@ createHTML: (html) => {
6231
6241
  const hasNextStep = /* @__PURE__ */ user_derived(() => !get(isLastStep));
6232
6242
  const hasPrevStep = /* @__PURE__ */ user_derived(() => get(stepIndex) > 0);
6233
6243
  const tourConfig = /* @__PURE__ */ user_derived(() => config.getConfig().tour);
6244
+ /**
6245
+ * Verifies the current step's target resolved to a DOM element.
6246
+ *
6247
+ * Emits {@link BordaEvent.ON_TOUR_ERROR} followed by {@link BordaEvent.ON_TOUR_CLOSE}
6248
+ * when it didn't, instead of leaving the widget rendering nothing for a step
6249
+ * the user can't see or dismiss.
6250
+ *
6251
+ * @returns `true` when there is no step, or its target resolved; `false` when the tour was closed due to an error.
6252
+ */
6253
+ function checkCurrentTarget() {
6254
+ if (!get(step) || get(currentTarget)) return true;
6255
+ const error = new BordaError(`Borda: target for step ${get(currentStep)} did not resolve to an element.`);
6256
+ console.error(error);
6257
+ eventEmitter.emit(BordaEvent.ON_TOUR_ERROR, error);
6258
+ eventEmitter.emit(BordaEvent.ON_TOUR_CLOSE);
6259
+ return false;
6260
+ }
6234
6261
  function apply() {
6235
6262
  set(stepIndex, get(tourConfig)?.startStep ?? 0, true);
6236
6263
  get(tourConfig)?.onStart?.();
@@ -6244,6 +6271,7 @@ createHTML: (html) => {
6244
6271
  await entering?.prepareElement?.();
6245
6272
  entering?.onBeforeHighlighted?.();
6246
6273
  set(stepIndex, index, true);
6274
+ if (!checkCurrentTarget()) return;
6247
6275
  entering?.onHighlighted?.();
6248
6276
  eventEmitter.emit(BordaEvent.ON_TOUR_STEP_CHANGE, get(currentStep));
6249
6277
  }
@@ -6335,7 +6363,8 @@ createHTML: (html) => {
6335
6363
  prev,
6336
6364
  next,
6337
6365
  finish
6338
- }
6366
+ },
6367
+ checkCurrentTarget
6339
6368
  };
6340
6369
  }
6341
6370
  //#endregion
@@ -9213,6 +9242,11 @@ createHTML: (html) => {
9213
9242
  config.getConfig().tour?.onClose?.();
9214
9243
  await unmount$1(instance);
9215
9244
  });
9245
+ eventEmitter.once(BordaEvent.ON_TOUR_ERROR, (error) => {
9246
+ config.getConfig().tour?.onError?.(error);
9247
+ });
9248
+ /** Validate the initial step now that ON_TOUR_ERROR/ON_TOUR_CLOSE listeners above are registered. */
9249
+ controller.checkCurrentTarget();
9216
9250
  resolve(instance);
9217
9251
  },
9218
9252
  unmount: () => {
@@ -9255,7 +9289,7 @@ createHTML: (html) => {
9255
9289
  }
9256
9290
  return {
9257
9291
  NAME: "@retoo/borda",
9258
- VERSION: "0.0.1",
9292
+ VERSION: "0.1.0",
9259
9293
  mount: mount$1,
9260
9294
  unmount: unmount$1,
9261
9295
  highlight: useBordaHighlight(mount$1).highlight
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ declare enum BordaEvent {
16
16
  ON_TOUR_NEXT = "tour:next",
17
17
  /** Fired when navigating to the previous step. */
18
18
  ON_TOUR_PREV = "tour:prev",
19
+ /** Fired when a step's target fails to resolve to a DOM element, just before the tour closes. */
20
+ ON_TOUR_ERROR = "tour:error",
19
21
  /** Fired when the ArrowRight key is pressed during an active tour. */
20
22
  ON_KEYBOARD_NEXT = "keyboard:next",
21
23
  /** Fired when the ArrowLeft key is pressed during an active tour. */
@@ -39,11 +41,11 @@ type BordaEventMap<T = unknown> = Map<BordaEvent, Set<BordaEventHandler<T>>>;
39
41
  /** Pub/sub event bus for communication between borda components. */
40
42
  interface BordaEventEmitter {
41
43
  /** Subscribe a handler to an event. */
42
- on(eventName: BordaEvent, handler: BordaEventHandler): void;
44
+ on<T = unknown>(eventName: BordaEvent, handler: BordaEventHandler<T>): void;
43
45
  /** Subscribe a handler to an event; auto-unsubscribes after first call. */
44
- once(eventName: BordaEvent, handler: BordaEventHandler): void;
46
+ once<T = unknown>(eventName: BordaEvent, handler: BordaEventHandler<T>): void;
45
47
  /** Unsubscribe a specific handler from an event. */
46
- off(eventName: BordaEvent, handler: BordaEventHandler): void;
48
+ off<T = unknown>(eventName: BordaEvent, handler: BordaEventHandler<T>): void;
47
49
  /** Emit an event, calling all subscribed handlers with optional data. */
48
50
  emit<T>(eventName: BordaEvent, data?: T): void;
49
51
  /** Remove all handlers for a specific event. */
@@ -888,6 +890,8 @@ interface UseBordaControllerReturns {
888
890
  apply: () => void;
889
891
  /** Reactive public API for controlling the tour. */
890
892
  api: BordaControllerApi;
893
+ /** Verifies the current step's target resolved; closes the tour and returns `false` if not. */
894
+ checkCurrentTarget: () => boolean;
891
895
  }
892
896
 
893
897
  /**
@@ -1226,6 +1230,17 @@ interface BordaTourProgressRef {
1226
1230
  getElements: () => BordaTourProgressElements;
1227
1231
  }
1228
1232
 
1233
+ /**
1234
+ * Base error class for all borda runtime errors.
1235
+ *
1236
+ * Using a named subclass makes borda errors easy to identify
1237
+ * in stack traces and `instanceof` checks.
1238
+ */
1239
+ declare class BordaError extends Error {
1240
+ readonly name = "BordaError";
1241
+ constructor(message: string);
1242
+ }
1243
+
1229
1244
  /** Props for the BordaTour step composition component. */
1230
1245
  interface BordaTourProps {
1231
1246
  step: BordaStep;
@@ -1235,9 +1250,7 @@ interface BordaTourProps {
1235
1250
  size: ComponentSize;
1236
1251
  shape: ComponentShape;
1237
1252
  isSkipChecked: boolean;
1238
- /** Hides the tooltip (fade transition) while scrolling/transitioning between steps. */
1239
1253
  isHidden: boolean;
1240
- /** Enables position gliding of the tooltip between steps (glide transition). */
1241
1254
  hasGlide: boolean;
1242
1255
  tourTooltipAnimation: BordaTourTooltipAnimation | false;
1243
1256
  tourTooltipProps: Partial<BordaTourTooltipProps>;
@@ -1280,6 +1293,8 @@ interface BordaTourConfig {
1280
1293
  onFinish: () => void;
1281
1294
  /** Called when the tour is dismissed before completion (close button, backdrop or Escape), before the unmount animation. */
1282
1295
  onClose: () => void;
1296
+ /** Called when a step's target fails to resolve to a DOM element, just before the tour closes. */
1297
+ onError: (error: BordaError) => void;
1283
1298
  /**
1284
1299
  * Enable keyboard navigation: ArrowRight/ArrowLeft for next/prev, Escape to close.
1285
1300
  * Defaults to `true`. Set to `false` to disable all keyboard handling.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retoo/borda",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Embeddable onboarding widget for any website. Framework-agnostic, SSR-safe.",
5
5
  "keywords": [
6
6
  "embeddable",