@guidelytech/guide-runtime 0.15.0 → 0.17.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.
Files changed (46) hide show
  1. package/dist/bug-report.cjs +340 -0
  2. package/dist/bug-report.cjs.map +1 -0
  3. package/dist/bug-report.d.cts +38 -0
  4. package/dist/bug-report.d.ts +38 -0
  5. package/dist/bug-report.js +213 -0
  6. package/dist/bug-report.js.map +1 -0
  7. package/dist/capture.cjs +5 -0
  8. package/dist/capture.cjs.map +1 -1
  9. package/dist/capture.js +32 -420
  10. package/dist/capture.js.map +1 -1
  11. package/dist/{chunk-VJSQM23R.js → chunk-63M4VHQG.js} +6 -6
  12. package/dist/chunk-63M4VHQG.js.map +1 -0
  13. package/dist/{chunk-VQJ7MZ2K.js → chunk-EPR4LWA2.js} +2 -2
  14. package/dist/{chunk-H3CROHPR.js → chunk-QFKMXMM4.js} +2 -2
  15. package/dist/chunk-THGKUOHM.js +445 -0
  16. package/dist/chunk-THGKUOHM.js.map +1 -0
  17. package/dist/chunk-V6TY7KAL.js +8 -0
  18. package/dist/chunk-V6TY7KAL.js.map +1 -0
  19. package/dist/index.cjs +100 -24
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +11 -4
  22. package/dist/index.d.ts +11 -4
  23. package/dist/index.js +87 -15
  24. package/dist/index.js.map +1 -1
  25. package/dist/messenger.js +3 -2
  26. package/dist/messenger.js.map +1 -1
  27. package/package.json +9 -4
  28. package/dist/chunk-4FKYF6OB.js +0 -466
  29. package/dist/chunk-4FKYF6OB.js.map +0 -1
  30. package/dist/chunk-4UW6YF44.js +0 -464
  31. package/dist/chunk-4UW6YF44.js.map +0 -1
  32. package/dist/chunk-7DOGZKWD.js +0 -322
  33. package/dist/chunk-7DOGZKWD.js.map +0 -1
  34. package/dist/chunk-GUH2PQJ7.js +0 -462
  35. package/dist/chunk-GUH2PQJ7.js.map +0 -1
  36. package/dist/chunk-GUSKGNNR.js +0 -301
  37. package/dist/chunk-GUSKGNNR.js.map +0 -1
  38. package/dist/chunk-KJRXCITD.js +0 -515
  39. package/dist/chunk-KJRXCITD.js.map +0 -1
  40. package/dist/chunk-PG7CMBHD.js +0 -330
  41. package/dist/chunk-PG7CMBHD.js.map +0 -1
  42. package/dist/chunk-VJSQM23R.js.map +0 -1
  43. package/dist/chunk-VNJPNGZ4.js +0 -301
  44. package/dist/chunk-VNJPNGZ4.js.map +0 -1
  45. /package/dist/{chunk-VQJ7MZ2K.js.map → chunk-EPR4LWA2.js.map} +0 -0
  46. /package/dist/{chunk-H3CROHPR.js.map → chunk-QFKMXMM4.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -44,9 +44,9 @@ __export(src_exports, {
44
44
  generateSelectors: () => generateSelectors,
45
45
  highlightSelectors: () => highlightSelectors,
46
46
  isAnchoredStep: () => isAnchoredStep,
47
- isChecklistComplete: () => import_runtime7.isChecklistComplete,
47
+ isChecklistComplete: () => import_runtime8.isChecklistComplete,
48
48
  isGuidelyElement: () => isGuidelyElement,
49
- isQuestionVisible: () => import_runtime8.isQuestionVisible,
49
+ isQuestionVisible: () => import_runtime9.isQuestionVisible,
50
50
  isStableClass: () => isStableClass,
51
51
  isStableId: () => isStableId,
52
52
  isVisible: () => isVisible,
@@ -665,6 +665,11 @@ var STYLES = `
665
665
  .g-close:hover,.g-close:focus-visible{background:var(--g-subtle);color:var(--g-text);outline:none}
666
666
  .g-close:focus-visible,.g-btn:focus-visible,.g-task:focus-visible,.g-choice:focus-visible,.g-scale button:focus-visible,.g-launcher:focus-visible,.g-input:focus-visible,.g-rc-item:focus-visible{outline:2px solid var(--g-primary);outline-offset:2px}
667
667
  .g-image{display:block;width:100%;max-height:220px;object-fit:cover;border-radius:var(--g-radius) var(--g-radius) 0 0}
668
+ .g-video{position:relative;display:block;width:100%;aspect-ratio:16/9;max-height:240px;overflow:hidden;background:#0f172a;border-radius:var(--g-radius) var(--g-radius) 0 0;cursor:pointer}
669
+ .g-video-poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
670
+ .g-video-play{position:absolute;left:50%;top:50%;width:56px;height:56px;margin:-28px 0 0 -28px;display:flex;align-items:center;justify-content:center;padding-left:3px;box-sizing:border-box;border-radius:999px;background:rgba(15,23,42,.72);color:#fff;box-shadow:0 4px 14px rgba(0,0,0,.3);transition:transform .15s ease,background .15s ease}
671
+ .g-video:hover .g-video-play,.g-video:focus-visible .g-video-play{transform:scale(1.08);background:var(--g-primary);color:var(--g-primary-text)}
672
+ .g-video:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px}
668
673
  .g-title{margin:0 28px 6px 0;font-size:16px;font-weight:600;line-height:1.3}
669
674
  .g-body{font-size:14px;color:var(--g-text)}
670
675
  .g-body p{margin:0 0 8px}.g-body p:last-child{margin-bottom:0}
@@ -1191,6 +1196,7 @@ function trackRect(el2, cb) {
1191
1196
 
1192
1197
  // src/render.ts
1193
1198
  var import_shared = require("@guidelytech/shared");
1199
+ var import_runtime6 = require("@guidelytech/shared/runtime");
1194
1200
  var FOCUSABLE = "button:not([disabled]),[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex='-1'])";
1195
1201
  var uid = 0;
1196
1202
  var nextId = (p) => `g-${p}-${++uid}`;
@@ -1212,6 +1218,52 @@ function buildButtons(doc, step, canGoBack, onButton) {
1212
1218
  return btn;
1213
1219
  });
1214
1220
  }
1221
+ var SVG_NS = "http://www.w3.org/2000/svg";
1222
+ function playIcon(doc) {
1223
+ const svg = doc.createElementNS(SVG_NS, "svg");
1224
+ svg.setAttribute("viewBox", "0 0 24 24");
1225
+ svg.setAttribute("width", "22");
1226
+ svg.setAttribute("height", "22");
1227
+ svg.setAttribute("aria-hidden", "true");
1228
+ const path = doc.createElementNS(SVG_NS, "path");
1229
+ path.setAttribute("fill", "currentColor");
1230
+ path.setAttribute("d", "M8 5.5v13a.75.75 0 0 0 1.14.64l10.4-6.5a.75.75 0 0 0 0-1.28L9.14 4.86A.75.75 0 0 0 8 5.5Z");
1231
+ svg.appendChild(path);
1232
+ return svg;
1233
+ }
1234
+ function buildVideo(doc, step, video, onVideo) {
1235
+ const a = h(doc, "a", "g-video");
1236
+ a.href = video.url;
1237
+ a.target = "_blank";
1238
+ a.rel = "noopener noreferrer";
1239
+ const opened = (e) => {
1240
+ if (e.type === "auxclick" && e.button !== 1) return;
1241
+ onVideo?.(video.url);
1242
+ };
1243
+ a.addEventListener("click", opened);
1244
+ a.addEventListener("auxclick", opened);
1245
+ a.setAttribute("aria-label", `${step.title ? `Play video: ${step.title}` : "Play video"} (opens in a new tab)`);
1246
+ if (video.poster) {
1247
+ const img = h(doc, "img", "g-video-poster");
1248
+ img.src = video.poster;
1249
+ img.alt = "";
1250
+ img.addEventListener("error", () => img.remove());
1251
+ a.appendChild(img);
1252
+ } else if ((0, import_runtime6.isVideoFileUrl)(video.url)) {
1253
+ const v = h(doc, "video", "g-video-poster");
1254
+ v.src = `${video.url}#t=0.1`;
1255
+ v.preload = "metadata";
1256
+ v.muted = true;
1257
+ v.playsInline = true;
1258
+ v.tabIndex = -1;
1259
+ v.setAttribute("aria-hidden", "true");
1260
+ a.appendChild(v);
1261
+ }
1262
+ const play = h(doc, "span", "g-video-play");
1263
+ play.appendChild(playIcon(doc));
1264
+ a.appendChild(play);
1265
+ return a;
1266
+ }
1215
1267
  function buildCard(doc, opts, extraClass) {
1216
1268
  const { step } = opts;
1217
1269
  const card = h(doc, "div", `g-card ${extraClass}`);
@@ -1220,7 +1272,10 @@ function buildCard(doc, opts, extraClass) {
1220
1272
  if (step.width) card.style.width = `min(${step.width}px, calc(100vw - 32px))`;
1221
1273
  const titleId = nextId("title");
1222
1274
  const bodyId = nextId("body");
1223
- if (step.imageUrl) {
1275
+ const video = (0, import_runtime6.stepVideo)(step);
1276
+ if (video) {
1277
+ card.appendChild(buildVideo(doc, step, video, opts.onVideo));
1278
+ } else if (step.imageUrl) {
1224
1279
  const img = h(doc, "img", "g-image");
1225
1280
  img.src = step.imageUrl;
1226
1281
  img.alt = step.imageAlt ?? "";
@@ -1623,7 +1678,7 @@ function isAnchoredStep(step) {
1623
1678
  }
1624
1679
 
1625
1680
  // src/controller.ts
1626
- var import_runtime6 = require("@guidelytech/shared/runtime");
1681
+ var import_runtime7 = require("@guidelytech/shared/runtime");
1627
1682
  function noop() {
1628
1683
  }
1629
1684
  var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
@@ -1728,7 +1783,7 @@ function runGuide(guide, options = {}) {
1728
1783
  const ctx = getCtx();
1729
1784
  if (step && ctx) {
1730
1785
  for (const branch of step.branches) {
1731
- if ((0, import_runtime6.evaluateRules)(branch.when, ctx)) {
1786
+ if ((0, import_runtime7.evaluateRules)(branch.when, ctx)) {
1732
1787
  target = steps.findIndex((s) => s.id === branch.goTo);
1733
1788
  if (target >= 0) break;
1734
1789
  }
@@ -1837,6 +1892,7 @@ function runGuide(guide, options = {}) {
1837
1892
  const render = (step, target, asModal = false) => {
1838
1893
  if (ended) return;
1839
1894
  status = "running";
1895
+ const shownIndex = index;
1840
1896
  const shown = !target && step.advanceOn === "element_click" && !step.advanceValue && !step.buttons.length ? { ...step, buttons: [{ id: "g-next", label: index + 1 >= total ? "Done" : "Next", action: index + 1 >= total ? "complete" : "next", variant: "primary" }] } : step;
1841
1897
  try {
1842
1898
  view = renderStep({
@@ -1849,6 +1905,7 @@ function runGuide(guide, options = {}) {
1849
1905
  asModal,
1850
1906
  onButton: handleButton,
1851
1907
  onClose: () => end("dismissed"),
1908
+ onVideo: (url) => emit("guide_video_clicked", step, shownIndex, { videoUrl: url }),
1852
1909
  announce,
1853
1910
  runCode: options.runCode,
1854
1911
  onError
@@ -1859,6 +1916,20 @@ function runGuide(guide, options = {}) {
1859
1916
  if (index + 1 < total) return goNext();
1860
1917
  return end("skipped");
1861
1918
  }
1919
+ if (view && options.onAction) {
1920
+ const shownView = view;
1921
+ shownView.el.addEventListener("click", (e) => {
1922
+ const link = composedTarget(e)?.closest?.("a[href]");
1923
+ const articleId = (0, import_runtime7.articleIdFromHref)(link?.getAttribute("href"));
1924
+ if (!articleId) return;
1925
+ e.preventDefault();
1926
+ options.onAction?.("open_article", articleId);
1927
+ if (step.type === "modal" || step.type === "spotlight" || asModal || shownView.el.querySelector(".g-overlay, .g-spot-rect")) {
1928
+ completeStep();
1929
+ end(shownIndex + 1 >= total ? "completed" : "dismissed");
1930
+ }
1931
+ });
1932
+ }
1862
1933
  if (!started) {
1863
1934
  started = true;
1864
1935
  emit("guide_started", step, index);
@@ -1877,6 +1948,7 @@ function runGuide(guide, options = {}) {
1877
1948
  title: "Continue on another page",
1878
1949
  body: `<p>The next step${step.title ? `, <strong>${escapeHtml(step.title)}</strong>,` : ""} is on <code>${escapeHtml(where)}</code>.</p>`,
1879
1950
  imageUrl: "",
1951
+ videoUrl: "",
1880
1952
  buttons: [
1881
1953
  ...href ? [{ id: "g-go", label: "Take me there", action: "url", value: href, variant: "primary" }] : [],
1882
1954
  { id: "g-exit", label: "Exit", action: "dismiss", variant: href ? "secondary" : "primary" }
@@ -1921,7 +1993,7 @@ function runGuide(guide, options = {}) {
1921
1993
  index = i;
1922
1994
  const step = steps[i];
1923
1995
  const ctx = getCtx();
1924
- if (step.targeting && step.targeting.rules.length && ctx && !(0, import_runtime6.evaluateRules)(step.targeting, ctx)) {
1996
+ if (step.targeting && step.targeting.rules.length && ctx && !(0, import_runtime7.evaluateRules)(step.targeting, ctx)) {
1925
1997
  const nextIndex = i + direction;
1926
1998
  if (nextIndex >= total) return end("completed");
1927
1999
  if (nextIndex < 0) return;
@@ -2026,7 +2098,7 @@ function runGuide(guide, options = {}) {
2026
2098
  }
2027
2099
 
2028
2100
  // src/checklist.ts
2029
- var import_runtime7 = require("@guidelytech/shared/runtime");
2101
+ var import_runtime8 = require("@guidelytech/shared/runtime");
2030
2102
  function renderChecklist(options) {
2031
2103
  const { scope, config } = options;
2032
2104
  const doc = scope.ownerDocument;
@@ -2101,7 +2173,7 @@ function renderChecklist(options) {
2101
2173
  bar.setAttribute("aria-valuemax", "100");
2102
2174
  body.textContent = "";
2103
2175
  foot.textContent = "";
2104
- const complete = (0, import_runtime7.isChecklistComplete)(config, progress);
2176
+ const complete = (0, import_runtime8.isChecklistComplete)(config, progress);
2105
2177
  if (complete) {
2106
2178
  const wrap = doc.createElement("div");
2107
2179
  wrap.className = "g-complete";
@@ -2189,7 +2261,7 @@ function renderChecklist(options) {
2189
2261
  }
2190
2262
 
2191
2263
  // src/survey.ts
2192
- var import_runtime8 = require("@guidelytech/shared/runtime");
2264
+ var import_runtime9 = require("@guidelytech/shared/runtime");
2193
2265
  function renderSurvey(options) {
2194
2266
  const { scope, config } = options;
2195
2267
  const doc = scope.ownerDocument;
@@ -2381,14 +2453,14 @@ function renderSurvey(options) {
2381
2453
  config.questions.forEach((q) => {
2382
2454
  const el2 = questionEls.get(q.id);
2383
2455
  if (!el2) return;
2384
- const visible = (0, import_runtime8.isQuestionVisible)(q, answers);
2456
+ const visible = (0, import_runtime9.isQuestionVisible)(q, answers);
2385
2457
  el2.hidden = !visible;
2386
2458
  if (!visible && answers[q.id] !== void 0) delete answers[q.id];
2387
2459
  });
2388
2460
  }
2389
2461
  form.addEventListener("submit", (e) => {
2390
2462
  e.preventDefault();
2391
- const missing = config.questions.filter((q) => q.required && (0, import_runtime8.isQuestionVisible)(q, answers) && answers[q.id] === void 0);
2463
+ const missing = config.questions.filter((q) => q.required && (0, import_runtime9.isQuestionVisible)(q, answers) && answers[q.id] === void 0);
2392
2464
  if (missing.length) {
2393
2465
  errorEl.textContent = `Please answer: ${missing.map((q) => q.title).join(", ")}`;
2394
2466
  questionEls.get(missing[0].id)?.querySelector("button,textarea")?.focus();
@@ -2437,10 +2509,10 @@ function renderSurvey(options) {
2437
2509
  }
2438
2510
 
2439
2511
  // src/resource-center.ts
2440
- var import_runtime10 = require("@guidelytech/shared/runtime");
2512
+ var import_runtime11 = require("@guidelytech/shared/runtime");
2441
2513
 
2442
2514
  // src/help-view.ts
2443
- var import_runtime9 = require("@guidelytech/shared/runtime");
2515
+ var import_runtime10 = require("@guidelytech/shared/runtime");
2444
2516
  var SHOW_ME_KINDS = /* @__PURE__ */ new Set(["flow", "modal", "tooltip", "announcement"]);
2445
2517
  function startableGuide(guides, keyOrId) {
2446
2518
  if (!keyOrId || !guides) return null;
@@ -2459,8 +2531,8 @@ function resultRow(doc, icon, title, summary, onOpen, showMe) {
2459
2531
  return row;
2460
2532
  }
2461
2533
  function enhanceShowMe(root, doc, canStart, start) {
2462
- for (const a of Array.from(root.querySelectorAll(`a[href^="${import_runtime9.SHOW_ME_HREF_PREFIX}"]`))) {
2463
- const key = (0, import_runtime9.showMeKeyFromHref)(a.getAttribute("href"));
2534
+ for (const a of Array.from(root.querySelectorAll(`a[href^="${import_runtime10.SHOW_ME_HREF_PREFIX}"]`))) {
2535
+ const key = (0, import_runtime10.showMeKeyFromHref)(a.getAttribute("href"));
2464
2536
  const holder = a.closest("p.gd-show-me") ?? a;
2465
2537
  if (!key || !canStart(key)) {
2466
2538
  if (holder !== a) holder.remove();
@@ -2576,10 +2648,10 @@ function createHelpView(options) {
2576
2648
  const data = options.data();
2577
2649
  const member = options.audienceIds?.() ?? [];
2578
2650
  searchWrap.hidden = !!data.modules && !data.modules.includes("search");
2579
- const sections = (0, import_runtime9.resourceCenterSections)(data.collections, data.articles, member);
2651
+ const sections = (0, import_runtime10.resourceCenterSections)(data.collections, data.articles, member);
2580
2652
  const q = query.trim().toLowerCase();
2581
2653
  if (q) {
2582
- const walkthroughs = (data.recommended ?? []).filter((g) => (0, import_runtime9.matchesHelpQuery)(g.name, q) && startableGuide(options.guides?.() ?? data.recommended, g.id));
2654
+ const walkthroughs = (data.recommended ?? []).filter((g) => (0, import_runtime10.matchesHelpQuery)(g.name, q) && startableGuide(options.guides?.() ?? data.recommended, g.id));
2583
2655
  if (walkthroughs.length) {
2584
2656
  section(`Walkthroughs (${walkthroughs.length})`);
2585
2657
  for (const g of walkthroughs) body.appendChild(resultRow(doc, "\u25B6", g.name, "Show me, step by step", () => options.onStartGuide?.(g.id)));
@@ -2588,10 +2660,10 @@ function createHelpView(options) {
2588
2660
  body.append(...options.extra?.(q) ?? []);
2589
2661
  if (q) {
2590
2662
  const visible = sections.flatMap((s) => s.articles);
2591
- const local = visible.filter((a) => (0, import_runtime9.matchesHelpQuery)(`${a.title} ${a.summary}`, q));
2663
+ const local = visible.filter((a) => (0, import_runtime10.matchesHelpQuery)(`${a.title} ${a.summary}`, q));
2592
2664
  const seen = new Set(local.map((a) => a.id));
2593
2665
  const hidden = new Set(data.articles.map((a) => a.id).filter((id) => !visible.some((v) => v.id === id)));
2594
- const merged = [...local, ...serverResults.filter((a) => !seen.has(a.id) && !hidden.has(a.id) && (0, import_runtime9.isArticleListed)(data.collections, a, member))];
2666
+ const merged = [...local, ...serverResults.filter((a) => !seen.has(a.id) && !hidden.has(a.id) && (0, import_runtime10.isArticleListed)(data.collections, a, member))];
2595
2667
  section(`Results (${merged.length})`);
2596
2668
  if (!merged.length) body.appendChild(el(doc, "div", "g-rc-empty", "No articles match your search."));
2597
2669
  merged.forEach(articleButton);
@@ -2611,7 +2683,7 @@ function createHelpView(options) {
2611
2683
  },
2612
2684
  announcements: () => {
2613
2685
  if (!data.announcements?.length) return;
2614
- section(import_runtime9.RC_MODULE_LABELS.announcements);
2686
+ section(import_runtime10.RC_MODULE_LABELS.announcements);
2615
2687
  const seen = data.announcementsSeenAt ? Date.parse(data.announcementsSeenAt) : NaN;
2616
2688
  data.announcements.slice(0, 20).forEach((n) => body.appendChild(announcementItem(n, Number.isNaN(seen) || Date.parse(n.publishedAt) > seen)));
2617
2689
  },
@@ -2673,7 +2745,7 @@ function createHelpView(options) {
2673
2745
  });
2674
2746
  }
2675
2747
  };
2676
- for (const id of data.modules ?? import_runtime9.RC_MODULE_IDS) renderers[id]?.();
2748
+ for (const id of data.modules ?? import_runtime10.RC_MODULE_IDS) renderers[id]?.();
2677
2749
  if (!body.childNodes.length) body.appendChild(el(doc, "div", "g-rc-empty", "Nothing here yet."));
2678
2750
  }
2679
2751
  function announcementItem(n, unread) {
@@ -2798,10 +2870,10 @@ function renderResourceCenter(options) {
2798
2870
  const badge = el(doc, "span", "g-launcher-badge");
2799
2871
  badge.hidden = true;
2800
2872
  launcher.appendChild(badge);
2801
- const modules = () => (0, import_runtime10.orderedModules)(config.modules).filter((m) => m.enabled && (!("targeting" in m) || !m.targeting || !options.evaluate || options.evaluate(m.targeting))).map((m) => m.id);
2802
- const announcements = () => modules().includes("announcements") ? (0, import_runtime10.visibleAnnouncements)(config.announcements, options.audienceIds?.() ?? []) : [];
2873
+ const modules = () => (0, import_runtime11.orderedModules)(config.modules).filter((m) => m.enabled && (!("targeting" in m) || !m.targeting || !options.evaluate || options.evaluate(m.targeting))).map((m) => m.id);
2874
+ const announcements = () => modules().includes("announcements") ? (0, import_runtime11.visibleAnnouncements)(config.announcements, options.audienceIds?.() ?? []) : [];
2803
2875
  const updateBadge = () => {
2804
- const unread = (0, import_runtime10.unreadAnnouncements)(announcements(), options.announcementsSeenAt?.());
2876
+ const unread = (0, import_runtime11.unreadAnnouncements)(announcements(), options.announcementsSeenAt?.());
2805
2877
  badge.hidden = unread === 0;
2806
2878
  badge.textContent = unread > 9 ? "9+" : String(unread);
2807
2879
  const label = config.launcher.label || config.title;
@@ -2881,6 +2953,10 @@ function renderResourceCenter(options) {
2881
2953
  return {
2882
2954
  el: root,
2883
2955
  open: () => setOpen(true),
2956
+ openArticle(id) {
2957
+ setOpen(true);
2958
+ help.openArticle(id);
2959
+ },
2884
2960
  close: () => setOpen(false),
2885
2961
  toggle: () => setOpen(!open),
2886
2962
  isOpen: () => open,