@guidelytech/react-native 0.15.0 → 0.16.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/README.md +1 -1
- package/dist/index.cjs +104 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +113 -22
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ tasks).
|
|
|
76
76
|
|
|
77
77
|
| | |
|
|
78
78
|
|---|---|
|
|
79
|
-
| `useGuidely()` | Client: `identify(id, traits?, account?)`, `setAccount`, `updateTraits`, `reset()`, `track(name, props?)`, `screen(name)`, `startGuide(idOrKey)`, `stopGuide()`, `dismissGuide()`, `openChecklist(key)`, `closeChecklist(key)`, `completeChecklistTask(key, taskId)`, `openResourceCenter()`, `closeResourceCenter()`, `refresh()`, `setConsent()`, `on(event, cb)`, `getGuides()`, `getActiveGuide()`, `getState()`, `startSessionRecording()`, `stopSessionRecording()`, `isRecording()`, `getSessionId()` |
|
|
79
|
+
| `useGuidely()` | Client: `identify(id, traits?, account?)`, `setAccount`, `updateTraits`, `reset()`, `track(name, props?)`, `screen(name)`, `startGuide(idOrKey)`, `stopGuide()`, `dismissGuide()`, `openChecklist(key)`, `closeChecklist(key)`, `completeChecklistTask(key, taskId)`, `openResourceCenter()`, `closeResourceCenter()`, `openArticle(articleId)`, `refresh()`, `setConsent()`, `on(event, cb)`, `getGuides()`, `getActiveGuide()`, `getState()`, `startSessionRecording()`, `stopSessionRecording()`, `isRecording()`, `getSessionId()` |
|
|
80
80
|
| `useGuidelyReady()` | `true` once config is loaded |
|
|
81
81
|
| `useGuidelyIdentify(id, traits?, account?)` | Identify when the signed-in user changes |
|
|
82
82
|
| `useGuidelyScreen(name)` | Report a screen view from a component |
|
package/dist/index.cjs
CHANGED
|
@@ -165,7 +165,7 @@ function FlagsProvider({ children, client: external, payload, ...options }) {
|
|
|
165
165
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlagsContext.Provider, { value, children });
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
// ../shared/dist/chunk-
|
|
168
|
+
// ../shared/dist/chunk-7PWYIAJI.js
|
|
169
169
|
function fnv1a(input) {
|
|
170
170
|
let h = 2166136261;
|
|
171
171
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -574,6 +574,16 @@ function isSafeMediaUrl(url) {
|
|
|
574
574
|
return false;
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
|
+
function videoThumbnailUrl(url) {
|
|
578
|
+
const embed = url ? toEmbedUrl(url) : null;
|
|
579
|
+
if (embed?.provider !== "youtube") return null;
|
|
580
|
+
const id = embed.src.split("/embed/")[1]?.split("?")[0];
|
|
581
|
+
return id ? `https://i.ytimg.com/vi/${id}/hqdefault.jpg` : null;
|
|
582
|
+
}
|
|
583
|
+
function stepVideo(step) {
|
|
584
|
+
if (!step.videoUrl || !isSafeMediaUrl(step.videoUrl)) return null;
|
|
585
|
+
return { url: step.videoUrl, poster: (step.imageUrl && isSafeMediaUrl(step.imageUrl) ? step.imageUrl : null) ?? videoThumbnailUrl(step.videoUrl) };
|
|
586
|
+
}
|
|
577
587
|
var MAX_COLLECTION_DEPTH = 3;
|
|
578
588
|
function matchesAudiences(required, member) {
|
|
579
589
|
if (!required || required.length === 0) return true;
|
|
@@ -643,6 +653,13 @@ function unreadAnnouncements(items, lastSeenAt) {
|
|
|
643
653
|
if (Number.isNaN(seen)) return items.length;
|
|
644
654
|
return items.filter((a) => Date.parse(a.publishedAt) > seen).length;
|
|
645
655
|
}
|
|
656
|
+
var ARTICLE_HREF_PREFIX = "#guidely-article:";
|
|
657
|
+
var ARTICLE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
658
|
+
function articleIdFromHref(href) {
|
|
659
|
+
if (!href || !href.startsWith(ARTICLE_HREF_PREFIX)) return null;
|
|
660
|
+
const id = href.slice(ARTICLE_HREF_PREFIX.length);
|
|
661
|
+
return ARTICLE_ID.test(id) ? id : null;
|
|
662
|
+
}
|
|
646
663
|
var CAPTURE_SCREENSHOT_MAX_BYTES = 8 * 1024 * 1024;
|
|
647
664
|
var DEFAULT_LOCALE = "en";
|
|
648
665
|
function normalizeLocale(input) {
|
|
@@ -2969,7 +2986,7 @@ var PersistentStore = class {
|
|
|
2969
2986
|
|
|
2970
2987
|
// src/core/client.ts
|
|
2971
2988
|
var SDK_NAME = "@guidelytech/react-native";
|
|
2972
|
-
var SDK_VERSION = "0.
|
|
2989
|
+
var SDK_VERSION = "0.16.0";
|
|
2973
2990
|
var DEFAULT_API_URL = "https://guidelytech.com";
|
|
2974
2991
|
var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
|
|
2975
2992
|
var CACHED_START_MS = 1500;
|
|
@@ -3021,6 +3038,8 @@ var GuidelyClient = class {
|
|
|
3021
3038
|
__publicField(this, "expanded", /* @__PURE__ */ new Set());
|
|
3022
3039
|
__publicField(this, "surveyView", null);
|
|
3023
3040
|
__publicField(this, "resourceCenterOpen", false);
|
|
3041
|
+
/** The article a help-article link asked the resource center to show (`seq` tells repeats apart). */
|
|
3042
|
+
__publicField(this, "resourceCenterArticle", null);
|
|
3024
3043
|
__publicField(this, "cleanups", []);
|
|
3025
3044
|
__publicField(this, "timers", /* @__PURE__ */ new Set());
|
|
3026
3045
|
__publicField(this, "visibilityWatchers", /* @__PURE__ */ new Map());
|
|
@@ -4186,6 +4205,8 @@ var GuidelyClient = class {
|
|
|
4186
4205
|
*/
|
|
4187
4206
|
navigate(url) {
|
|
4188
4207
|
if (!url) return;
|
|
4208
|
+
const articleId = articleIdFromHref(url);
|
|
4209
|
+
if (articleId) return this.openArticle(articleId);
|
|
4189
4210
|
try {
|
|
4190
4211
|
if (this.options.onNavigate?.(url) === true) return;
|
|
4191
4212
|
if (/^[a-z][a-z0-9+.-]*:/i.test(url)) this.bridge.openExternal(url);
|
|
@@ -4209,7 +4230,7 @@ var GuidelyClient = class {
|
|
|
4209
4230
|
for (const f of [...this.flows.values(), ...this.active ? [this.active] : []]) if (f.view) steps.push({ ...f.view, expanded: this.expanded.has(f.guide.id) });
|
|
4210
4231
|
const checklists = [];
|
|
4211
4232
|
this.checklists.forEach((w, id) => checklists.push({ guide: w.guide, progress: this.getChecklistProgress(id), open: w.open }));
|
|
4212
|
-
this.ui = { steps, checklists, survey: this.surveyView, resourceCenterOpen: this.resourceCenterOpen, theme: this.themeFor(), messenger: !!this.messenger };
|
|
4233
|
+
this.ui = { steps, checklists, survey: this.surveyView, resourceCenterOpen: this.resourceCenterOpen, resourceCenterArticle: this.resourceCenterArticle, theme: this.themeFor(), messenger: !!this.messenger };
|
|
4213
4234
|
for (const cb of Array.from(this.uiListeners)) {
|
|
4214
4235
|
try {
|
|
4215
4236
|
cb();
|
|
@@ -4229,6 +4250,12 @@ var GuidelyClient = class {
|
|
|
4229
4250
|
closeStep(guideId) {
|
|
4230
4251
|
this.flowFor(guideId)?.controller.dismiss();
|
|
4231
4252
|
}
|
|
4253
|
+
/** The video on a step was tapped: records `guide_video_clicked`, then opens the video outside the app. */
|
|
4254
|
+
openVideo(guideId, url) {
|
|
4255
|
+
const v = this.flowFor(guideId)?.view;
|
|
4256
|
+
if (v) this.enqueue("guide_video_clicked", { guideId: v.guide.id, guideVersion: v.guide.version, stepId: v.step.id, stepIndex: v.index, properties: { videoUrl: url } });
|
|
4257
|
+
this.navigate(url);
|
|
4258
|
+
}
|
|
4232
4259
|
/** The dimmed backdrop behind a step was tapped. */
|
|
4233
4260
|
backdropPressed(guideId) {
|
|
4234
4261
|
const f = this.flowFor(guideId);
|
|
@@ -4501,10 +4528,40 @@ var GuidelyClient = class {
|
|
|
4501
4528
|
this.emitter.emit("resource-center:open");
|
|
4502
4529
|
this.notify();
|
|
4503
4530
|
}
|
|
4531
|
+
/**
|
|
4532
|
+
* Opens one help article: in Scout's Help tab when the messenger is on, otherwise in the resource
|
|
4533
|
+
* center. Help-article links in guides and articles (`#guidely-article:<id>`) call this.
|
|
4534
|
+
*/
|
|
4535
|
+
openArticle(articleId) {
|
|
4536
|
+
if (this.messenger) {
|
|
4537
|
+
this.whenHydrated(() => void this.messenger?.openArticle(articleId));
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4540
|
+
if (!this.getResourceCenter()) {
|
|
4541
|
+
this.log("openArticle: the resource center is not enabled or published for this environment");
|
|
4542
|
+
return;
|
|
4543
|
+
}
|
|
4544
|
+
this.resourceCenterArticle = { id: articleId, seq: (this.resourceCenterArticle?.seq ?? 0) + 1 };
|
|
4545
|
+
if (this.resourceCenterOpen) this.notify();
|
|
4546
|
+
else this.openResourceCenter();
|
|
4547
|
+
}
|
|
4548
|
+
/** A resource-center article with its body: from the config, or fetched when the config left it out. */
|
|
4549
|
+
async loadArticle(articleId) {
|
|
4550
|
+
const listed = this.getResourceCenter()?.articles.find((a) => a.id === articleId);
|
|
4551
|
+
if (listed && !listed.bodyOmitted) return listed;
|
|
4552
|
+
try {
|
|
4553
|
+
const locale = this.articleLocale();
|
|
4554
|
+
const res = await this.api.get(`/articles/${encodeURIComponent(articleId)}`, locale ? { params: { locale } } : {});
|
|
4555
|
+
return res.ok && res.data ? res.data.article : null;
|
|
4556
|
+
} catch {
|
|
4557
|
+
return null;
|
|
4558
|
+
}
|
|
4559
|
+
}
|
|
4504
4560
|
closeResourceCenter() {
|
|
4505
4561
|
if (this.messenger) return this.closeMessenger();
|
|
4506
4562
|
if (!this.resourceCenterOpen) return;
|
|
4507
4563
|
this.resourceCenterOpen = false;
|
|
4564
|
+
this.resourceCenterArticle = null;
|
|
4508
4565
|
this.notify();
|
|
4509
4566
|
}
|
|
4510
4567
|
// ---------------------------------------------------------------------------
|
|
@@ -5850,7 +5907,7 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
5850
5907
|
var import_react4 = require("react");
|
|
5851
5908
|
var import_react_native6 = require("react-native");
|
|
5852
5909
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
5853
|
-
function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
5910
|
+
function ResourceCenter({ client, palette: p, open, articleRequest, topInset, bottomInset }) {
|
|
5854
5911
|
const rc = client.getResourceCenter();
|
|
5855
5912
|
const [query, setQuery] = (0, import_react4.useState)("");
|
|
5856
5913
|
const [results, setResults] = (0, import_react4.useState)(null);
|
|
@@ -5863,6 +5920,19 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
5863
5920
|
setArticle(null);
|
|
5864
5921
|
}
|
|
5865
5922
|
}, [open]);
|
|
5923
|
+
(0, import_react4.useEffect)(() => {
|
|
5924
|
+
if (!open || !articleRequest) return;
|
|
5925
|
+
let alive = true;
|
|
5926
|
+
void client.loadArticle(articleRequest.id).then((a) => {
|
|
5927
|
+
if (!alive || !a) return;
|
|
5928
|
+
if (a.externalUrl) return client.navigate(a.externalUrl);
|
|
5929
|
+
client.articleViewed(a);
|
|
5930
|
+
setArticle(a);
|
|
5931
|
+
});
|
|
5932
|
+
return () => {
|
|
5933
|
+
alive = false;
|
|
5934
|
+
};
|
|
5935
|
+
}, [client, open, articleRequest?.seq]);
|
|
5866
5936
|
(0, import_react4.useEffect)(() => {
|
|
5867
5937
|
const q = query.trim();
|
|
5868
5938
|
if (q.length < 2) {
|
|
@@ -6044,7 +6114,7 @@ function positionCard(target, size, viewport, insets, placement, offset) {
|
|
|
6044
6114
|
// src/ui/StepCard.tsx
|
|
6045
6115
|
var import_react_native7 = require("react-native");
|
|
6046
6116
|
var import_jsx_runtime7 = (
|
|
6047
|
-
//
|
|
6117
|
+
// The video opens outside the app (browser or the provider's app), like a new tab on the web.
|
|
6048
6118
|
require("react/jsx-runtime")
|
|
6049
6119
|
);
|
|
6050
6120
|
function StepCard({ view, client, palette: p, width, style, compact }) {
|
|
@@ -6053,16 +6123,33 @@ function StepCard({ view, client, palette: p, width, style, compact }) {
|
|
|
6053
6123
|
const body = step.type === "custom" ? step.customHtml || step.body : step.body;
|
|
6054
6124
|
const showProgress = step.showProgress && view.total > 1;
|
|
6055
6125
|
const onLink = (url) => client.navigate(url);
|
|
6126
|
+
const video = stepVideo(step);
|
|
6056
6127
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Surface, { palette: p, style: [{ width }, style], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { accessible: false, accessibilityViewIsModal: view.asModal || step.type === "modal", style: compact ? styles6.compact : styles6.inner, children: [
|
|
6057
|
-
|
|
6058
|
-
import_react_native7.
|
|
6128
|
+
video ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
6129
|
+
import_react_native7.Pressable,
|
|
6059
6130
|
{
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6131
|
+
onPress: () => client.openVideo(guide.id, video.url),
|
|
6132
|
+
accessibilityRole: "button",
|
|
6133
|
+
accessibilityLabel: step.title ? `Play video: ${step.title}` : "Play video",
|
|
6134
|
+
accessibilityHint: "Opens the video outside the app",
|
|
6135
|
+
style: [styles6.video, { borderRadius: Math.max(0, p.radius - 4) }],
|
|
6136
|
+
children: [
|
|
6137
|
+
video.poster ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.Image, { source: { uri: video.poster }, style: import_react_native7.StyleSheet.absoluteFill, resizeMode: "cover", accessibilityIgnoresInvertColors: true, accessible: false }) : null,
|
|
6138
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: styles6.play, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: styles6.playTriangle }) })
|
|
6139
|
+
]
|
|
6065
6140
|
}
|
|
6141
|
+
) : step.imageUrl ? (
|
|
6142
|
+
// An empty description marks the image as decorative: screen readers skip it.
|
|
6143
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
6144
|
+
import_react_native7.Image,
|
|
6145
|
+
{
|
|
6146
|
+
source: { uri: step.imageUrl },
|
|
6147
|
+
style: [styles6.image, { borderRadius: Math.max(0, p.radius - 4) }],
|
|
6148
|
+
resizeMode: "cover",
|
|
6149
|
+
accessibilityIgnoresInvertColors: true,
|
|
6150
|
+
...step.imageAlt?.trim() ? { accessible: true, accessibilityRole: "image", accessibilityLabel: step.imageAlt.trim() } : { accessible: false, importantForAccessibility: "no" }
|
|
6151
|
+
}
|
|
6152
|
+
)
|
|
6066
6153
|
) : null,
|
|
6067
6154
|
step.title ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: styles6.header, children: [
|
|
6068
6155
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.Text, { accessibilityRole: "header", style: [styles6.title, { color: p.text, fontFamily: p.fontFamily }], children: step.title }),
|
|
@@ -6092,6 +6179,10 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
6092
6179
|
inner: { padding: 16, gap: 10 },
|
|
6093
6180
|
compact: { paddingHorizontal: 14, paddingVertical: 10, gap: 6 },
|
|
6094
6181
|
image: { width: "100%", height: 140, marginBottom: 2 },
|
|
6182
|
+
video: { width: "100%", aspectRatio: 16 / 9, maxHeight: 200, marginBottom: 2, overflow: "hidden", backgroundColor: "#0f172a", alignItems: "center", justifyContent: "center" },
|
|
6183
|
+
play: { width: 52, height: 52, borderRadius: 26, backgroundColor: "rgba(15,23,42,0.72)", alignItems: "center", justifyContent: "center", paddingLeft: 4 },
|
|
6184
|
+
// A CSS-border triangle: no icon font needed.
|
|
6185
|
+
playTriangle: { width: 0, height: 0, borderTopWidth: 10, borderBottomWidth: 10, borderLeftWidth: 16, borderTopColor: "transparent", borderBottomColor: "transparent", borderLeftColor: "#fff" },
|
|
6095
6186
|
header: { flexDirection: "row", alignItems: "flex-start", gap: 8 },
|
|
6096
6187
|
title: { flex: 1, fontSize: 17, fontWeight: "700", lineHeight: 22 },
|
|
6097
6188
|
flex: { flex: 1 },
|
|
@@ -6683,7 +6774,7 @@ function GuidelyOverlay({ client, insets: insetsProp, launcherOffset }) {
|
|
|
6683
6774
|
) : null,
|
|
6684
6775
|
ui.survey ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Survey, { view: ui.survey, client, palette: palette(client.themeFor(ui.survey.guide), scheme), geometry }) : null,
|
|
6685
6776
|
ui.steps.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StepLayer, { view: s, client, palette: palette(client.themeFor(s.guide), scheme, s.guide.config.appearance), geometry }, s.key)),
|
|
6686
|
-
messenger ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessengerSheet, { store: messenger, client, palette: basePalette, topInset: insets.top, bottomInset: insets.bottom }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ResourceCenter, { client, palette: basePalette, open: ui.resourceCenterOpen, topInset: insets.top, bottomInset: insets.bottom })
|
|
6777
|
+
messenger ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessengerSheet, { store: messenger, client, palette: basePalette, topInset: insets.top, bottomInset: insets.bottom }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ResourceCenter, { client, palette: basePalette, open: ui.resourceCenterOpen, articleRequest: ui.resourceCenterArticle ?? null, topInset: insets.top, bottomInset: insets.bottom })
|
|
6687
6778
|
] });
|
|
6688
6779
|
}
|
|
6689
6780
|
var styles9 = import_react_native10.StyleSheet.create({
|