@guidelytech/react-native 0.4.1 → 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.cjs +385 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +481 -156
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3,10 +3,10 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
5
|
// src/index.tsx
|
|
6
|
-
import { useContext as useContext2, useEffect as
|
|
6
|
+
import { useContext as useContext2, useEffect as useEffect8, useRef as useRef5, useState as useState7 } from "react";
|
|
7
7
|
import { AppState, Dimensions, Linking, Platform as Platform6 } from "react-native";
|
|
8
8
|
|
|
9
|
-
// ../shared/dist/chunk-
|
|
9
|
+
// ../shared/dist/chunk-OLWGMDRX.js
|
|
10
10
|
function fnv1a(input) {
|
|
11
11
|
let h = 2166136261;
|
|
12
12
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -310,8 +310,194 @@ function sanitizeProperties(props) {
|
|
|
310
310
|
return out;
|
|
311
311
|
}
|
|
312
312
|
var SOURCEMAP_MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
313
|
+
var MEDIA_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
314
|
+
var MEDIA_VIDEO_MAX_BYTES = 200 * 1024 * 1024;
|
|
315
|
+
var MEDIA_FILE_MAX_BYTES = 50 * 1024 * 1024;
|
|
316
|
+
var MEDIA_MAX_BYTES = Math.max(MEDIA_IMAGE_MAX_BYTES, MEDIA_VIDEO_MAX_BYTES, MEDIA_FILE_MAX_BYTES);
|
|
317
|
+
var FILE_LINK_CLASS = "gd-file";
|
|
318
|
+
var PDF_BLOCK_CLASS = "gd-pdf";
|
|
319
|
+
function isFileLink(className, href) {
|
|
320
|
+
return !!className && className.split(/\s+/).includes(FILE_LINK_CLASS) && isSafeMediaUrl(href);
|
|
321
|
+
}
|
|
322
|
+
var YOUTUBE_ID = /^[A-Za-z0-9_-]{11}$/;
|
|
323
|
+
var VIMEO_ID = /^\d{1,12}$/;
|
|
324
|
+
var VIMEO_HASH = /^[0-9a-f]{6,20}$/i;
|
|
325
|
+
var LOOM_ID = /^[0-9a-f]{32}$/i;
|
|
326
|
+
var WISTIA_ID = /^[a-z0-9]{10}$/i;
|
|
327
|
+
function parseUrl(input) {
|
|
328
|
+
const s = input.trim();
|
|
329
|
+
if (!s) return null;
|
|
330
|
+
try {
|
|
331
|
+
const u = new URL(/^[a-z][a-z0-9+.-]*:/i.test(s) ? s : `https://${s}`);
|
|
332
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return null;
|
|
333
|
+
if (u.username || u.password || u.port && u.port !== "443" && u.port !== "80") return null;
|
|
334
|
+
return u;
|
|
335
|
+
} catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function parseStart(v) {
|
|
340
|
+
if (!v) return 0;
|
|
341
|
+
if (/^\d+$/.test(v)) return Math.min(Number(v), 86400);
|
|
342
|
+
const m = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/.exec(v);
|
|
343
|
+
if (!m || !m[0]) return 0;
|
|
344
|
+
return Math.min(Number(m[1] ?? 0) * 3600 + Number(m[2] ?? 0) * 60 + Number(m[3] ?? 0), 86400);
|
|
345
|
+
}
|
|
346
|
+
function youtube(id, start) {
|
|
347
|
+
if (!YOUTUBE_ID.test(id)) return null;
|
|
348
|
+
return {
|
|
349
|
+
provider: "youtube",
|
|
350
|
+
src: `https://www.youtube-nocookie.com/embed/${id}${start ? `?start=${start}` : ""}`,
|
|
351
|
+
watchUrl: `https://www.youtube.com/watch?v=${id}${start ? `&t=${start}s` : ""}`,
|
|
352
|
+
title: "YouTube video"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function vimeo(id, hash) {
|
|
356
|
+
if (!VIMEO_ID.test(id) || hash !== null && !VIMEO_HASH.test(hash)) return null;
|
|
357
|
+
const h = hash ? hash.toLowerCase() : null;
|
|
358
|
+
return { provider: "vimeo", src: `https://player.vimeo.com/video/${id}${h ? `?h=${h}` : ""}`, watchUrl: `https://vimeo.com/${id}${h ? `/${h}` : ""}`, title: "Vimeo video" };
|
|
359
|
+
}
|
|
360
|
+
function toEmbedUrl(input) {
|
|
361
|
+
const u = parseUrl(input);
|
|
362
|
+
if (!u) return null;
|
|
363
|
+
const host = u.hostname.toLowerCase().replace(/^www\./, "");
|
|
364
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
365
|
+
switch (host) {
|
|
366
|
+
case "youtube.com":
|
|
367
|
+
case "m.youtube.com":
|
|
368
|
+
case "youtube-nocookie.com": {
|
|
369
|
+
const start = parseStart(u.searchParams.get("start") ?? u.searchParams.get("t"));
|
|
370
|
+
if (parts[0] === "watch" && parts.length === 1) return youtube(u.searchParams.get("v") ?? "", start);
|
|
371
|
+
if ((parts[0] === "embed" || parts[0] === "shorts" || parts[0] === "live") && parts.length === 2) return youtube(parts[1], start);
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
case "youtu.be":
|
|
375
|
+
return parts.length === 1 ? youtube(parts[0], parseStart(u.searchParams.get("t") ?? u.searchParams.get("start"))) : null;
|
|
376
|
+
case "vimeo.com":
|
|
377
|
+
if (parts.length === 1) return vimeo(parts[0], null);
|
|
378
|
+
if (parts.length === 2 && VIMEO_ID.test(parts[0])) return vimeo(parts[0], parts[1]);
|
|
379
|
+
return null;
|
|
380
|
+
case "player.vimeo.com":
|
|
381
|
+
return parts[0] === "video" && parts.length === 2 ? vimeo(parts[1], u.searchParams.get("h")) : null;
|
|
382
|
+
case "loom.com":
|
|
383
|
+
if ((parts[0] === "share" || parts[0] === "embed") && parts.length === 2 && LOOM_ID.test(parts[1])) {
|
|
384
|
+
const id = parts[1].toLowerCase();
|
|
385
|
+
return { provider: "loom", src: `https://www.loom.com/embed/${id}`, watchUrl: `https://www.loom.com/share/${id}`, title: "Loom video" };
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
default: {
|
|
389
|
+
let id;
|
|
390
|
+
if (host === "fast.wistia.net" || host === "fast.wistia.com") id = parts[0] === "embed" && parts[1] === "iframe" && parts.length === 3 ? parts[2] : void 0;
|
|
391
|
+
else if (host === "wi.st" || host === "wistia.com" || /^[a-z0-9-]+\.wistia\.com$/.test(host)) id = parts[0] === "medias" && parts.length === 2 ? parts[1] : void 0;
|
|
392
|
+
if (!id || !WISTIA_ID.test(id)) return null;
|
|
393
|
+
return { provider: "wistia", src: `https://fast.wistia.net/embed/iframe/${id}`, watchUrl: `https://fast.wistia.net/embed/iframe/${id}`, title: "Wistia video" };
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function isAllowedEmbedSrc(src) {
|
|
398
|
+
if (!src) return false;
|
|
399
|
+
return toEmbedUrl(src)?.src === src;
|
|
400
|
+
}
|
|
401
|
+
function isSafeMediaUrl(url) {
|
|
402
|
+
if (!url) return false;
|
|
403
|
+
try {
|
|
404
|
+
const u = new URL(url);
|
|
405
|
+
return (u.protocol === "https:" || u.protocol === "http:") && !u.username && !u.password;
|
|
406
|
+
} catch {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
var MAX_COLLECTION_DEPTH = 3;
|
|
411
|
+
function matchesAudiences(required, member) {
|
|
412
|
+
if (!required || required.length === 0) return true;
|
|
413
|
+
if (!member) return false;
|
|
414
|
+
const has2 = member instanceof Set ? (id) => member.has(id) : (id) => member.includes(id);
|
|
415
|
+
return required.some(has2);
|
|
416
|
+
}
|
|
417
|
+
function resourceCenterSections(collections, articles, member) {
|
|
418
|
+
const byId = new Map(collections.map((c) => [c.id, c]));
|
|
419
|
+
const children = /* @__PURE__ */ new Map();
|
|
420
|
+
for (const c of collections) {
|
|
421
|
+
const parent = c.parentId && c.parentId !== c.id && byId.has(c.parentId) ? c.parentId : null;
|
|
422
|
+
const list = children.get(parent) ?? [];
|
|
423
|
+
list.push(c);
|
|
424
|
+
children.set(parent, list);
|
|
425
|
+
}
|
|
426
|
+
for (const list of children.values()) list.sort((a, b) => a.order - b.order || a.name.localeCompare(b.name));
|
|
427
|
+
const direct = /* @__PURE__ */ new Map();
|
|
428
|
+
const uncategorized = [];
|
|
429
|
+
for (const a of articles) {
|
|
430
|
+
if (!matchesAudiences(a.audienceIds, member)) continue;
|
|
431
|
+
if (a.collectionId && byId.has(a.collectionId)) {
|
|
432
|
+
const list = direct.get(a.collectionId) ?? [];
|
|
433
|
+
list.push(a);
|
|
434
|
+
direct.set(a.collectionId, list);
|
|
435
|
+
} else uncategorized.push(a);
|
|
436
|
+
}
|
|
437
|
+
const sections = [];
|
|
438
|
+
const seen = /* @__PURE__ */ new Set();
|
|
439
|
+
const visit = (c, path) => {
|
|
440
|
+
if (seen.has(c.id)) return;
|
|
441
|
+
seen.add(c.id);
|
|
442
|
+
if (!matchesAudiences(c.audienceIds, member)) return;
|
|
443
|
+
const here = [...path, c.name];
|
|
444
|
+
const list = direct.get(c.id);
|
|
445
|
+
if (list?.length) sections.push({ collection: c, path: here, depth: here.length - 1, articles: list });
|
|
446
|
+
for (const child of children.get(c.id) ?? []) visit(child, here);
|
|
447
|
+
};
|
|
448
|
+
for (const root of children.get(null) ?? []) visit(root, []);
|
|
449
|
+
if (uncategorized.length) sections.push({ collection: null, path: [], depth: 0, articles: uncategorized });
|
|
450
|
+
return sections;
|
|
451
|
+
}
|
|
452
|
+
function isArticleListed(collections, article, member) {
|
|
453
|
+
if (!matchesAudiences(article.audienceIds, member)) return false;
|
|
454
|
+
const byId = new Map(collections.map((c) => [c.id, c]));
|
|
455
|
+
let cur = article.collectionId ? byId.get(article.collectionId) : void 0;
|
|
456
|
+
for (let guard = 0; cur && guard <= MAX_COLLECTION_DEPTH * 4; guard++) {
|
|
457
|
+
if (!matchesAudiences(cur.audienceIds, member)) return false;
|
|
458
|
+
cur = cur.parentId ? byId.get(cur.parentId) : void 0;
|
|
459
|
+
}
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
var CAPTURE_SCREENSHOT_MAX_BYTES = 8 * 1024 * 1024;
|
|
313
463
|
|
|
314
|
-
// ../sdk-core/dist/chunk-
|
|
464
|
+
// ../sdk-core/dist/chunk-CYAG6ZYX.js
|
|
465
|
+
function readJson(store, key, fallback) {
|
|
466
|
+
const raw = store.get(key);
|
|
467
|
+
if (raw == null) return fallback;
|
|
468
|
+
try {
|
|
469
|
+
return JSON.parse(raw);
|
|
470
|
+
} catch {
|
|
471
|
+
return fallback;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function writeJson(store, key, value) {
|
|
475
|
+
try {
|
|
476
|
+
store.set(key, JSON.stringify(value));
|
|
477
|
+
} catch {
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
var KEYS = {
|
|
481
|
+
anon: "guidely:anon",
|
|
482
|
+
seen: "guidely:seen",
|
|
483
|
+
config: (key) => `guidely:config:${key}`,
|
|
484
|
+
etag: (key) => `guidely:etag:${key}`,
|
|
485
|
+
state: (key) => `guidely:state:${key}`,
|
|
486
|
+
user: (key) => `guidely:user:${key}`,
|
|
487
|
+
queue: (key) => `guidely:queue:${key}`,
|
|
488
|
+
session: "guidely:session",
|
|
489
|
+
active: "guidely:active",
|
|
490
|
+
authoring: "guidely:authoring",
|
|
491
|
+
/** How-to capture session marker ({ token, … }) and its not-yet-uploaded steps. */
|
|
492
|
+
capture: "guidely:capture",
|
|
493
|
+
capturePending: "guidely:capture:pending",
|
|
494
|
+
/** Messenger conversations this browser can read: [{ id, token }]. */
|
|
495
|
+
conversations: (key) => `guidely:conversations:${key}`,
|
|
496
|
+
/** Announcement ids opened in the messenger's News tab. */
|
|
497
|
+
newsSeen: (key) => `guidely:news:${key}`
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// ../sdk-core/dist/chunk-AKNE7D5M.js
|
|
315
501
|
var __defProp2 = Object.defineProperty;
|
|
316
502
|
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
317
503
|
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -333,7 +519,8 @@ var Api = class {
|
|
|
333
519
|
const f = this.fetcher;
|
|
334
520
|
if (!f) throw new Error("fetch is not available");
|
|
335
521
|
const headers = { ...options.headers, "X-Guidely-Key": this.key, Accept: "application/json" };
|
|
336
|
-
|
|
522
|
+
const form = typeof FormData !== "undefined" && options.body instanceof FormData;
|
|
523
|
+
if (options.body !== void 0 && !form) headers["Content-Type"] = "application/json";
|
|
337
524
|
if (options.etag) headers["If-None-Match"] = options.etag;
|
|
338
525
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
339
526
|
const timer = ac ? setTimeout(() => ac.abort(), options.timeoutMs ?? 1e4) : null;
|
|
@@ -341,7 +528,7 @@ var Api = class {
|
|
|
341
528
|
const res = await f(this.url(path, options.params), {
|
|
342
529
|
method,
|
|
343
530
|
headers,
|
|
344
|
-
body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
|
|
531
|
+
body: options.body === void 0 ? void 0 : form ? options.body : JSON.stringify(options.body),
|
|
345
532
|
keepalive: options.keepalive,
|
|
346
533
|
signal: ac?.signal,
|
|
347
534
|
credentials: "omit",
|
|
@@ -366,6 +553,10 @@ var Api = class {
|
|
|
366
553
|
post(path, body, options) {
|
|
367
554
|
return this.request("POST", path, { body, ...options });
|
|
368
555
|
}
|
|
556
|
+
/** Multipart POST (file uploads). No Content-Type header: the browser adds it with the boundary. */
|
|
557
|
+
postForm(path, form, options) {
|
|
558
|
+
return this.request("POST", path, { body: form, ...options });
|
|
559
|
+
}
|
|
369
560
|
/**
|
|
370
561
|
* POST that may answer with server-sent events. Each event is passed to `onEvent`; a JSON answer is
|
|
371
562
|
* returned instead. No timeout: Scout replies can take a while and the server keeps the stream alive.
|
|
@@ -408,10 +599,10 @@ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
408
599
|
function backoffMs(attempt, baseMs = 1e3, maxMs = 3e4) {
|
|
409
600
|
return Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt));
|
|
410
601
|
}
|
|
411
|
-
async function
|
|
602
|
+
async function withRetry(send, attempts = 3, baseMs = 500) {
|
|
412
603
|
for (let i = 0; i < attempts; i++) {
|
|
413
604
|
try {
|
|
414
|
-
const res = await
|
|
605
|
+
const res = await send();
|
|
415
606
|
if (res.ok || res.status >= 400 && res.status < 500 && res.status !== 429) return res;
|
|
416
607
|
} catch {
|
|
417
608
|
}
|
|
@@ -419,6 +610,9 @@ async function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
|
|
|
419
610
|
}
|
|
420
611
|
return null;
|
|
421
612
|
}
|
|
613
|
+
function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
|
|
614
|
+
return withRetry(() => api.post(path, body), attempts, baseMs);
|
|
615
|
+
}
|
|
422
616
|
async function readEventStream(body, onEvent) {
|
|
423
617
|
const reader = body.getReader();
|
|
424
618
|
const decoder = new TextDecoder();
|
|
@@ -453,36 +647,7 @@ async function readEventStream(body, onEvent) {
|
|
|
453
647
|
if (buffer.trim()) dispatch(buffer);
|
|
454
648
|
}
|
|
455
649
|
|
|
456
|
-
// ../sdk-core/dist/chunk-
|
|
457
|
-
function readJson(store, key, fallback) {
|
|
458
|
-
const raw = store.get(key);
|
|
459
|
-
if (raw == null) return fallback;
|
|
460
|
-
try {
|
|
461
|
-
return JSON.parse(raw);
|
|
462
|
-
} catch {
|
|
463
|
-
return fallback;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
function writeJson(store, key, value) {
|
|
467
|
-
try {
|
|
468
|
-
store.set(key, JSON.stringify(value));
|
|
469
|
-
} catch {
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
var KEYS = {
|
|
473
|
-
anon: "guidely:anon",
|
|
474
|
-
seen: "guidely:seen",
|
|
475
|
-
config: (key) => `guidely:config:${key}`,
|
|
476
|
-
etag: (key) => `guidely:etag:${key}`,
|
|
477
|
-
state: (key) => `guidely:state:${key}`,
|
|
478
|
-
user: (key) => `guidely:user:${key}`,
|
|
479
|
-
queue: (key) => `guidely:queue:${key}`,
|
|
480
|
-
session: "guidely:session",
|
|
481
|
-
active: "guidely:active",
|
|
482
|
-
authoring: "guidely:authoring",
|
|
483
|
-
/** Messenger conversations this browser can read: [{ id, token }]. */
|
|
484
|
-
conversations: (key) => `guidely:conversations:${key}`
|
|
485
|
-
};
|
|
650
|
+
// ../sdk-core/dist/chunk-GDF6RCHQ.js
|
|
486
651
|
var EventQueue = class {
|
|
487
652
|
constructor(opts) {
|
|
488
653
|
__publicField2(this, "opts", opts);
|
|
@@ -1564,7 +1729,7 @@ var PersistentStore = class {
|
|
|
1564
1729
|
|
|
1565
1730
|
// src/core/client.ts
|
|
1566
1731
|
var SDK_NAME = "@guidelytech/react-native";
|
|
1567
|
-
var SDK_VERSION = "0.
|
|
1732
|
+
var SDK_VERSION = "0.6.1";
|
|
1568
1733
|
var DEFAULT_API_URL = "https://guidelytech.com";
|
|
1569
1734
|
var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
|
|
1570
1735
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2429,6 +2594,10 @@ var GuidelyClient = class {
|
|
|
2429
2594
|
if (this.activeSurvey?.guide.id !== guideId) return;
|
|
2430
2595
|
this.finishSurvey(this.surveyView?.submitted ? "submitted" : "dismissed");
|
|
2431
2596
|
}
|
|
2597
|
+
/** The visitor's audiences (from the last identify), for audience-targeted help articles. */
|
|
2598
|
+
getAudienceIds() {
|
|
2599
|
+
return this.state.audienceIds;
|
|
2600
|
+
}
|
|
2432
2601
|
getResourceCenter() {
|
|
2433
2602
|
const rc = this.config?.resourceCenter;
|
|
2434
2603
|
return rc && rc.enabled ? rc : null;
|
|
@@ -2693,11 +2862,11 @@ function forPlatform(config, platform) {
|
|
|
2693
2862
|
}
|
|
2694
2863
|
|
|
2695
2864
|
// src/ui/Overlay.tsx
|
|
2696
|
-
import { useCallback as useCallback2, useEffect as
|
|
2697
|
-
import { Platform as Platform5, Pressable as
|
|
2865
|
+
import { useCallback as useCallback2, useEffect as useEffect6, useRef as useRef3, useState as useState6, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
2866
|
+
import { Platform as Platform5, Pressable as Pressable8, StatusBar, StyleSheet as StyleSheet9, Text as Text8, useColorScheme, useWindowDimensions, View as View9 } from "react-native";
|
|
2698
2867
|
|
|
2699
2868
|
// src/ui/Checklist.tsx
|
|
2700
|
-
import { Pressable as
|
|
2869
|
+
import { Pressable as Pressable3, ScrollView as ScrollView2, StyleSheet as StyleSheet3, Text as Text3, View as View3 } from "react-native";
|
|
2701
2870
|
|
|
2702
2871
|
// src/ui/primitives.tsx
|
|
2703
2872
|
import { Pressable, StyleSheet, Text, View } from "react-native";
|
|
@@ -2751,8 +2920,8 @@ var styles = StyleSheet.create({
|
|
|
2751
2920
|
});
|
|
2752
2921
|
|
|
2753
2922
|
// src/ui/RichText.tsx
|
|
2754
|
-
import { useMemo } from "react";
|
|
2755
|
-
import { Platform, StyleSheet as StyleSheet2, Text as Text2, View as View2 } from "react-native";
|
|
2923
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2924
|
+
import { Image, Modal, Platform, Pressable as Pressable2, ScrollView, StyleSheet as StyleSheet2, Text as Text2, View as View2 } from "react-native";
|
|
2756
2925
|
|
|
2757
2926
|
// src/core/html.ts
|
|
2758
2927
|
var ENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: "\xA0", mdash: "\u2014", ndash: "\u2013", hellip: "\u2026", rsquo: "\u2019", lsquo: "\u2018", rdquo: "\u201D", ldquo: "\u201C", copy: "\xA9", reg: "\xAE", trade: "\u2122", times: "\xD7", rarr: "\u2192", larr: "\u2190", bull: "\u2022" };
|
|
@@ -2766,7 +2935,8 @@ function decodeEntities(s) {
|
|
|
2766
2935
|
});
|
|
2767
2936
|
}
|
|
2768
2937
|
var BLOCK_TAGS = /* @__PURE__ */ new Set(["p", "div", "section", "article", "header", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "li", "blockquote", "ul", "ol", "table", "tr", "pre"]);
|
|
2769
|
-
var SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "head", "title", "svg", "template"]);
|
|
2938
|
+
var SKIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "head", "title", "svg", "template", "iframe", "video"]);
|
|
2939
|
+
var PROVIDER_LABEL = { youtube: "Watch on YouTube", vimeo: "Watch on Vimeo", loom: "Watch on Loom", wistia: "Watch video" };
|
|
2770
2940
|
function attr(attrs, name) {
|
|
2771
2941
|
const m = attrs.match(new RegExp(`\\b${name}\\s*=\\s*("([^"]*)"|'([^']*)'|([^\\s>]+))`, "i"));
|
|
2772
2942
|
return m ? decodeEntities(m[2] ?? m[3] ?? m[4] ?? "") : void 0;
|
|
@@ -2778,6 +2948,12 @@ function parseHtml(html) {
|
|
|
2778
2948
|
const lists = [];
|
|
2779
2949
|
let current = null;
|
|
2780
2950
|
let skipping = null;
|
|
2951
|
+
let pdf = null;
|
|
2952
|
+
let fileLink = null;
|
|
2953
|
+
const media = (block) => {
|
|
2954
|
+
flush();
|
|
2955
|
+
blocks.push({ level: 1, runs: [], ...block });
|
|
2956
|
+
};
|
|
2781
2957
|
const flush = () => {
|
|
2782
2958
|
if (current) {
|
|
2783
2959
|
const runs = current.runs;
|
|
@@ -2808,12 +2984,30 @@ function parseHtml(html) {
|
|
|
2808
2984
|
if (last && last.bold === run.bold && last.italic === run.italic && last.underline === run.underline && last.code === run.code && last.href === run.href) last.text += text;
|
|
2809
2985
|
else current.runs.push(run);
|
|
2810
2986
|
};
|
|
2987
|
+
const size = (attrs, name) => {
|
|
2988
|
+
const n = Number(attr(attrs, name));
|
|
2989
|
+
return n > 0 ? n : void 0;
|
|
2990
|
+
};
|
|
2991
|
+
const endPdf = (p) => {
|
|
2992
|
+
const name = p.name.replace(/\s+/g, " ").trim();
|
|
2993
|
+
if (p.href && p.pages.length) media({ kind: "pdf", href: p.href, alt: name || "PDF", pages: p.pages });
|
|
2994
|
+
else if (p.href) media({ kind: "file", href: p.href, alt: name || "Open PDF" });
|
|
2995
|
+
else for (const page of p.pages) media({ kind: "image", src: page.src, alt: page.alt, ...page.width && page.height ? { width: page.width, height: page.height } : {} });
|
|
2996
|
+
};
|
|
2811
2997
|
const re = /<!--[\s\S]*?-->|<\/?([a-zA-Z][a-zA-Z0-9]*)\b([^>]*)>|([^<]+|<)/g;
|
|
2812
2998
|
let m;
|
|
2813
2999
|
while (m = re.exec(html || "")) {
|
|
2814
3000
|
const [token, rawTag, attrs = "", text] = m;
|
|
2815
3001
|
if (text !== void 0) {
|
|
2816
3002
|
if (skipping) continue;
|
|
3003
|
+
if (pdf) {
|
|
3004
|
+
if (pdf.inLink) pdf.name += decodeEntities(text);
|
|
3005
|
+
continue;
|
|
3006
|
+
}
|
|
3007
|
+
if (fileLink) {
|
|
3008
|
+
fileLink.name += decodeEntities(text);
|
|
3009
|
+
continue;
|
|
3010
|
+
}
|
|
2817
3011
|
push(decodeEntities(text.replace(/\s+/g, " ")));
|
|
2818
3012
|
continue;
|
|
2819
3013
|
}
|
|
@@ -2825,7 +3019,54 @@ function parseHtml(html) {
|
|
|
2825
3019
|
continue;
|
|
2826
3020
|
}
|
|
2827
3021
|
if (SKIP_TAGS.has(tag)) {
|
|
2828
|
-
if (
|
|
3022
|
+
if (closing) continue;
|
|
3023
|
+
if (tag === "iframe") {
|
|
3024
|
+
const src = attr(attrs, "src");
|
|
3025
|
+
const embed = isAllowedEmbedSrc(src) ? toEmbedUrl(src) : null;
|
|
3026
|
+
if (embed) media({ kind: "video", href: embed.watchUrl, alt: PROVIDER_LABEL[embed.provider] });
|
|
3027
|
+
} else if (tag === "video") {
|
|
3028
|
+
const src = attr(attrs, "src");
|
|
3029
|
+
if (isSafeMediaUrl(src)) media({ kind: "video", href: src, alt: "Play video" });
|
|
3030
|
+
}
|
|
3031
|
+
if (!token.endsWith("/>")) skipping = tag;
|
|
3032
|
+
continue;
|
|
3033
|
+
}
|
|
3034
|
+
if (pdf) {
|
|
3035
|
+
if (tag === "div") {
|
|
3036
|
+
pdf.depth += closing ? -1 : 1;
|
|
3037
|
+
if (pdf.depth === 0) {
|
|
3038
|
+
endPdf(pdf);
|
|
3039
|
+
pdf = null;
|
|
3040
|
+
}
|
|
3041
|
+
} else if (tag === "a") {
|
|
3042
|
+
if (closing) pdf.inLink = false;
|
|
3043
|
+
else if (!pdf.href && isFileLink(attr(attrs, "class"), attr(attrs, "href"))) {
|
|
3044
|
+
pdf.href = attr(attrs, "href");
|
|
3045
|
+
pdf.inLink = true;
|
|
3046
|
+
}
|
|
3047
|
+
} else if (tag === "img" && !closing) {
|
|
3048
|
+
const src = attr(attrs, "src");
|
|
3049
|
+
const w = size(attrs, "width");
|
|
3050
|
+
const h = size(attrs, "height");
|
|
3051
|
+
if (isSafeMediaUrl(src)) pdf.pages.push({ src, alt: attr(attrs, "alt") ?? "", ...w && h ? { width: w, height: h } : {} });
|
|
3052
|
+
}
|
|
3053
|
+
continue;
|
|
3054
|
+
}
|
|
3055
|
+
if (fileLink) {
|
|
3056
|
+
if (closing && tag === "a") {
|
|
3057
|
+
media({ kind: "file", href: fileLink.href, alt: fileLink.name.replace(/\s+/g, " ").trim() || "Open PDF" });
|
|
3058
|
+
fileLink = null;
|
|
3059
|
+
}
|
|
3060
|
+
continue;
|
|
3061
|
+
}
|
|
3062
|
+
if (!closing && tag === "div" && (attr(attrs, "class") ?? "").split(/\s+/).includes(PDF_BLOCK_CLASS)) {
|
|
3063
|
+
flush();
|
|
3064
|
+
pdf = { depth: 1, name: "", inLink: false, pages: [] };
|
|
3065
|
+
continue;
|
|
3066
|
+
}
|
|
3067
|
+
if (!closing && tag === "a" && isFileLink(attr(attrs, "class"), attr(attrs, "href"))) {
|
|
3068
|
+
flush();
|
|
3069
|
+
fileLink = { href: attr(attrs, "href"), name: "" };
|
|
2829
3070
|
continue;
|
|
2830
3071
|
}
|
|
2831
3072
|
if (closing) {
|
|
@@ -2886,16 +3127,23 @@ function parseHtml(html) {
|
|
|
2886
3127
|
default:
|
|
2887
3128
|
if (BLOCK_TAGS.has(tag)) open("paragraph");
|
|
2888
3129
|
else if (tag === "img") {
|
|
2889
|
-
const
|
|
2890
|
-
|
|
3130
|
+
const src = attr(attrs, "src") ?? "";
|
|
3131
|
+
const alt = attr(attrs, "alt") ?? "";
|
|
3132
|
+
if (isSafeMediaUrl(src) || /^data:image\//i.test(src)) {
|
|
3133
|
+
const w = Number(attr(attrs, "width"));
|
|
3134
|
+
const h = Number(attr(attrs, "height"));
|
|
3135
|
+
media({ kind: "image", src, alt, ...w > 0 && h > 0 ? { width: w, height: h } : {} });
|
|
3136
|
+
} else if (alt) push(alt);
|
|
2891
3137
|
}
|
|
2892
3138
|
}
|
|
2893
3139
|
}
|
|
3140
|
+
if (pdf) endPdf(pdf);
|
|
3141
|
+
if (fileLink) media({ kind: "file", href: fileLink.href, alt: fileLink.name.replace(/\s+/g, " ").trim() || "Open PDF" });
|
|
2894
3142
|
flush();
|
|
2895
3143
|
return blocks;
|
|
2896
3144
|
}
|
|
2897
3145
|
function htmlToText(html) {
|
|
2898
|
-
return parseHtml(html).map((b) => (b.marker ? `${b.marker} ` : "") + b.runs.map((r) => r.text).join("")).join("\n");
|
|
3146
|
+
return parseHtml(html).map((b) => b.kind === "image" || b.kind === "video" || b.kind === "pdf" || b.kind === "file" ? b.alt ?? "" : (b.marker ? `${b.marker} ` : "") + b.runs.map((r) => r.text).join("")).filter(Boolean).join("\n");
|
|
2899
3147
|
}
|
|
2900
3148
|
|
|
2901
3149
|
// src/ui/RichText.tsx
|
|
@@ -2912,11 +3160,76 @@ function runStyle(run, p) {
|
|
|
2912
3160
|
color: run.href ? p.primary : void 0
|
|
2913
3161
|
};
|
|
2914
3162
|
}
|
|
3163
|
+
function BodyImage({ block, palette: p }) {
|
|
3164
|
+
const [ratio, setRatio] = useState(block.width && block.height ? block.width / block.height : 16 / 9);
|
|
3165
|
+
useEffect(() => {
|
|
3166
|
+
if (block.width && block.height) return;
|
|
3167
|
+
let live = true;
|
|
3168
|
+
Image.getSize(block.src, (w, h) => live && w > 0 && h > 0 && setRatio(w / h), () => {
|
|
3169
|
+
});
|
|
3170
|
+
return () => {
|
|
3171
|
+
live = false;
|
|
3172
|
+
};
|
|
3173
|
+
}, [block.src, block.width, block.height]);
|
|
3174
|
+
return /* @__PURE__ */ jsx2(Image, { source: { uri: block.src }, accessible: true, accessibilityRole: "image", accessibilityLabel: block.alt || void 0, resizeMode: "contain", style: [styles2.image, { aspectRatio: ratio, backgroundColor: p.surface }] });
|
|
3175
|
+
}
|
|
3176
|
+
function BodyVideo({ block, palette: p, onLink }) {
|
|
3177
|
+
return /* @__PURE__ */ jsxs(Pressable2, { accessibilityRole: "link", accessibilityLabel: block.alt, onPress: () => onLink(block.href), style: ({ pressed }) => [styles2.video, { borderColor: p.border, backgroundColor: p.surface, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3178
|
+
/* @__PURE__ */ jsx2(Text2, { style: [styles2.play, { color: p.primary }], children: "\u25B6" }),
|
|
3179
|
+
/* @__PURE__ */ jsx2(Text2, { style: { color: p.primary, fontFamily: p.fontFamily, fontWeight: "600" }, children: block.alt })
|
|
3180
|
+
] });
|
|
3181
|
+
}
|
|
3182
|
+
var PAGE_RATIO = 1 / 1.414;
|
|
3183
|
+
var pageRatio = (p) => p.width && p.height ? p.width / p.height : PAGE_RATIO;
|
|
3184
|
+
function PdfBadge() {
|
|
3185
|
+
return /* @__PURE__ */ jsx2(View2, { style: styles2.badge, children: /* @__PURE__ */ jsx2(Text2, { style: styles2.badgeText, children: "PDF" }) });
|
|
3186
|
+
}
|
|
3187
|
+
function BodyFile({ block, palette: p, onLink }) {
|
|
3188
|
+
return /* @__PURE__ */ jsxs(Pressable2, { accessibilityRole: "link", accessibilityLabel: `${block.alt}, PDF`, onPress: () => onLink(block.href), style: ({ pressed }) => [styles2.video, { borderColor: p.border, backgroundColor: p.surface, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3189
|
+
/* @__PURE__ */ jsx2(PdfBadge, {}),
|
|
3190
|
+
/* @__PURE__ */ jsx2(Text2, { numberOfLines: 2, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt })
|
|
3191
|
+
] });
|
|
3192
|
+
}
|
|
3193
|
+
function BodyPdf({ block, palette: p, onLink }) {
|
|
3194
|
+
const pages = block.pages ?? [];
|
|
3195
|
+
const [width, setWidth] = useState(0);
|
|
3196
|
+
const [index, setIndex] = useState(0);
|
|
3197
|
+
const [reading, setReading] = useState(false);
|
|
3198
|
+
const height = width ? Math.max(...pages.map((pg) => width / pageRatio(pg))) : 0;
|
|
3199
|
+
const onScroll = (e) => width && setIndex(Math.round(e.nativeEvent.contentOffset.x / width));
|
|
3200
|
+
return /* @__PURE__ */ jsxs(View2, { style: [styles2.pdf, { borderColor: p.border, backgroundColor: p.surface }], children: [
|
|
3201
|
+
/* @__PURE__ */ jsxs(Pressable2, { accessibilityRole: "button", accessibilityLabel: `Read ${block.alt} full screen`, onPress: () => setReading(true), style: ({ pressed }) => [styles2.pdfHeader, { opacity: pressed ? 0.7 : 1 }], children: [
|
|
3202
|
+
/* @__PURE__ */ jsx2(PdfBadge, {}),
|
|
3203
|
+
/* @__PURE__ */ jsx2(Text2, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt }),
|
|
3204
|
+
/* @__PURE__ */ jsx2(Text2, { style: { color: p.muted, fontSize: 16 }, children: "\u2922" })
|
|
3205
|
+
] }),
|
|
3206
|
+
/* @__PURE__ */ jsxs(View2, { style: styles2.pdfPages, onLayout: (e) => setWidth(e.nativeEvent.layout.width), children: [
|
|
3207
|
+
width > 0 && /* @__PURE__ */ jsx2(ScrollView, { horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll, scrollEventThrottle: 32, accessibilityLabel: `${block.alt}, page ${index + 1} of ${pages.length}`, children: pages.map((pg, i) => /* @__PURE__ */ jsx2(Pressable2, { onPress: () => setReading(true), accessibilityRole: "imagebutton", accessibilityLabel: pg.alt || `Page ${i + 1}`, accessibilityHint: "Opens the document full screen", style: { width, height, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2(Image, { source: { uri: pg.src }, resizeMode: "contain", style: [styles2.page, { width: Math.min(width, height * pageRatio(pg)), aspectRatio: pageRatio(pg) }] }) }, i)) }),
|
|
3208
|
+
pages.length > 1 && /* @__PURE__ */ jsx2(View2, { pointerEvents: "none", style: styles2.count, children: /* @__PURE__ */ jsxs(Text2, { style: styles2.countText, children: [
|
|
3209
|
+
index + 1,
|
|
3210
|
+
" / ",
|
|
3211
|
+
pages.length
|
|
3212
|
+
] }) })
|
|
3213
|
+
] }),
|
|
3214
|
+
/* @__PURE__ */ jsx2(Modal, { visible: reading, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: () => setReading(false), children: /* @__PURE__ */ jsxs(View2, { style: styles2.reader, children: [
|
|
3215
|
+
/* @__PURE__ */ jsxs(View2, { style: styles2.readerBar, children: [
|
|
3216
|
+
/* @__PURE__ */ jsx2(Text2, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, styles2.readerTitle], accessibilityRole: "header", children: block.alt }),
|
|
3217
|
+
/* @__PURE__ */ jsx2(Pressable2, { accessibilityRole: "link", onPress: () => onLink(block.href), style: styles2.readerBtn, children: /* @__PURE__ */ jsx2(Text2, { style: styles2.readerBtnText, children: "Open PDF \u2197" }) }),
|
|
3218
|
+
/* @__PURE__ */ jsx2(Pressable2, { accessibilityRole: "button", accessibilityLabel: "Close", onPress: () => setReading(false), style: styles2.readerBtn, children: /* @__PURE__ */ jsx2(Text2, { style: styles2.readerBtnText, children: "Done" }) })
|
|
3219
|
+
] }),
|
|
3220
|
+
/* @__PURE__ */ jsx2(ScrollView, { contentContainerStyle: styles2.readerPages, children: pages.map((pg, i) => /* @__PURE__ */ jsx2(Image, { source: { uri: pg.src }, accessible: true, accessibilityLabel: pg.alt || `Page ${i + 1}`, resizeMode: "contain", style: [styles2.readerPage, { aspectRatio: pageRatio(pg) }] }, i)) })
|
|
3221
|
+
] }) })
|
|
3222
|
+
] });
|
|
3223
|
+
}
|
|
2915
3224
|
function RichText({ html, palette: p, onLink, size = 15 }) {
|
|
2916
3225
|
const blocks = useMemo(() => parseHtml(html), [html]);
|
|
2917
3226
|
if (!blocks.length) return null;
|
|
2918
3227
|
const base = { color: p.text, fontSize: size, lineHeight: Math.round(size * 1.42), fontFamily: p.fontFamily };
|
|
2919
3228
|
return /* @__PURE__ */ jsx2(View2, { style: styles2.wrap, children: blocks.map((b, i) => {
|
|
3229
|
+
if (b.kind === "image") return /* @__PURE__ */ jsx2(BodyImage, { block: b, palette: p }, i);
|
|
3230
|
+
if (b.kind === "video") return /* @__PURE__ */ jsx2(BodyVideo, { block: b, palette: p, onLink }, i);
|
|
3231
|
+
if (b.kind === "pdf") return /* @__PURE__ */ jsx2(BodyPdf, { block: b, palette: p, onLink }, i);
|
|
3232
|
+
if (b.kind === "file") return /* @__PURE__ */ jsx2(BodyFile, { block: b, palette: p, onLink }, i);
|
|
2920
3233
|
const runs = b.runs.map((r, j) => /* @__PURE__ */ jsx2(Text2, { style: runStyle(r, p), onPress: r.href ? () => onLink(r.href) : void 0, accessibilityRole: r.href ? "link" : void 0, children: r.text }, j));
|
|
2921
3234
|
if (b.kind === "list-item") {
|
|
2922
3235
|
return /* @__PURE__ */ jsxs(View2, { style: [styles2.li, { paddingLeft: (b.level - 1) * 14 }], children: [
|
|
@@ -2935,7 +3248,25 @@ var styles2 = StyleSheet2.create({
|
|
|
2935
3248
|
wrap: { gap: 6 },
|
|
2936
3249
|
li: { flexDirection: "row", gap: 6 },
|
|
2937
3250
|
marker: { minWidth: 14 },
|
|
2938
|
-
flex: { flex: 1 }
|
|
3251
|
+
flex: { flex: 1 },
|
|
3252
|
+
image: { width: "100%", borderRadius: 6 },
|
|
3253
|
+
video: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 12, paddingHorizontal: 14, borderWidth: 1, borderRadius: 8 },
|
|
3254
|
+
play: { fontSize: 14 },
|
|
3255
|
+
badge: { backgroundColor: "#e5484d", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 3 },
|
|
3256
|
+
badgeText: { color: "#fff", fontSize: 9, fontWeight: "700", letterSpacing: 0.4 },
|
|
3257
|
+
pdf: { borderWidth: 1, borderRadius: 10, overflow: "hidden" },
|
|
3258
|
+
pdfHeader: { flexDirection: "row", alignItems: "center", gap: 8, minHeight: 44, paddingHorizontal: 12 },
|
|
3259
|
+
pdfPages: { marginHorizontal: 10, marginBottom: 10 },
|
|
3260
|
+
page: { backgroundColor: "#fff", borderRadius: 3 },
|
|
3261
|
+
count: { position: "absolute", right: 8, bottom: 8, backgroundColor: "rgba(17,17,17,0.72)", borderRadius: 999, paddingHorizontal: 8, paddingVertical: 2 },
|
|
3262
|
+
countText: { color: "#fff", fontSize: 11, fontWeight: "500", fontVariant: ["tabular-nums"] },
|
|
3263
|
+
reader: { flex: 1, backgroundColor: "#0b0b0d" },
|
|
3264
|
+
readerBar: { flexDirection: "row", alignItems: "center", gap: 8, paddingTop: Platform.OS === "ios" ? 52 : 12, paddingBottom: 10, paddingHorizontal: 16 },
|
|
3265
|
+
readerTitle: { color: "#fff", fontSize: 16, fontWeight: "600" },
|
|
3266
|
+
readerBtn: { minHeight: 36, justifyContent: "center", paddingHorizontal: 12, borderRadius: 8, backgroundColor: "rgba(255,255,255,0.12)" },
|
|
3267
|
+
readerBtnText: { color: "#fff", fontWeight: "600" },
|
|
3268
|
+
readerPages: { gap: 12, paddingHorizontal: 12, paddingBottom: 32 },
|
|
3269
|
+
readerPage: { width: "100%", backgroundColor: "#fff", borderRadius: 2 }
|
|
2939
3270
|
});
|
|
2940
3271
|
|
|
2941
3272
|
// src/ui/Checklist.tsx
|
|
@@ -2969,11 +3300,11 @@ function Checklist({ view, client, palette: p, geometry, showLauncher, launcherB
|
|
|
2969
3300
|
] }),
|
|
2970
3301
|
/* @__PURE__ */ jsx3(View3, { style: [styles3.bar, { backgroundColor: p.surface }], accessibilityRole: "progressbar", accessibilityValue: { min: 0, max: total, now: completed }, children: /* @__PURE__ */ jsx3(View3, { style: [styles3.fill, { backgroundColor: p.primary, width: `${total ? completed / total * 100 : 0}%` }] }) }),
|
|
2971
3302
|
finished && config.completionBody ? /* @__PURE__ */ jsx3(RichText, { html: config.completionBody, palette: p, onLink: (u) => client.navigate(u), size: 14 }) : null,
|
|
2972
|
-
/* @__PURE__ */ jsx3(
|
|
3303
|
+
/* @__PURE__ */ jsx3(ScrollView2, { style: styles3.tasks, contentContainerStyle: styles3.tasksContent, children: config.tasks.map((task) => {
|
|
2973
3304
|
const isDone = done.has(task.id);
|
|
2974
3305
|
const locked = !!nextOpen && !isDone && task.id !== nextOpen;
|
|
2975
3306
|
return /* @__PURE__ */ jsxs2(
|
|
2976
|
-
|
|
3307
|
+
Pressable3,
|
|
2977
3308
|
{
|
|
2978
3309
|
disabled: locked,
|
|
2979
3310
|
accessibilityRole: "button",
|
|
@@ -2998,7 +3329,7 @@ function Checklist({ view, client, palette: p, geometry, showLauncher, launcherB
|
|
|
2998
3329
|
config.dismissible ? /* @__PURE__ */ jsx3(GButton, { label: finished ? "Close for good" : "Dismiss checklist", variant: "ghost", palette: p, onPress: () => client.dismissChecklist(view.guide.id), style: styles3.dismiss }) : null
|
|
2999
3330
|
] }) }) : null,
|
|
3000
3331
|
showLauncher ? /* @__PURE__ */ jsxs2(
|
|
3001
|
-
|
|
3332
|
+
Pressable3,
|
|
3002
3333
|
{
|
|
3003
3334
|
accessibilityRole: "button",
|
|
3004
3335
|
accessibilityLabel: `${config.launcherLabel}, ${completed} of ${total} complete`,
|
|
@@ -3051,8 +3382,8 @@ var styles3 = StyleSheet3.create({
|
|
|
3051
3382
|
});
|
|
3052
3383
|
|
|
3053
3384
|
// src/ui/Messenger.tsx
|
|
3054
|
-
import { useCallback, useEffect, useMemo as useMemo2, useRef, useState, useSyncExternalStore } from "react";
|
|
3055
|
-
import { ActivityIndicator, Keyboard, Modal, Platform as Platform2, Pressable as
|
|
3385
|
+
import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState2, useSyncExternalStore } from "react";
|
|
3386
|
+
import { ActivityIndicator, Keyboard, Modal as Modal2, Platform as Platform2, Pressable as Pressable4, ScrollView as ScrollView3, StyleSheet as StyleSheet4, Text as Text4, TextInput, View as View4 } from "react-native";
|
|
3056
3387
|
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
3057
3388
|
function useMessenger(store) {
|
|
3058
3389
|
return useSyncExternalStore(
|
|
@@ -3062,8 +3393,8 @@ function useMessenger(store) {
|
|
|
3062
3393
|
);
|
|
3063
3394
|
}
|
|
3064
3395
|
function useKeyboardHeight() {
|
|
3065
|
-
const [h, setH] =
|
|
3066
|
-
|
|
3396
|
+
const [h, setH] = useState2(0);
|
|
3397
|
+
useEffect2(() => {
|
|
3067
3398
|
if (Platform2.OS !== "ios") return;
|
|
3068
3399
|
const show = Keyboard.addListener("keyboardWillShow", (e) => setH(e.endCoordinates.height));
|
|
3069
3400
|
const hide = Keyboard.addListener("keyboardWillHide", () => setH(0));
|
|
@@ -3085,7 +3416,7 @@ function MessengerLauncher({ store, palette: p, style }) {
|
|
|
3085
3416
|
const snap = useMessenger(store);
|
|
3086
3417
|
if (snap.open) return null;
|
|
3087
3418
|
const label = snap.unread ? `Open ${snap.config.name}, ${snap.unread} unread` : `Open ${snap.config.name}`;
|
|
3088
|
-
return /* @__PURE__ */ jsxs3(
|
|
3419
|
+
return /* @__PURE__ */ jsxs3(Pressable4, { accessibilityRole: "button", accessibilityLabel: label, onPress: () => store.open(), style: ({ pressed }) => [styles4.launcher, style, { backgroundColor: p.primary, opacity: pressed ? 0.85 : 1 }], children: [
|
|
3089
3420
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.launcherIcon, { color: p.onPrimary }], children: "\u{1F4AC}" }),
|
|
3090
3421
|
snap.unread ? /* @__PURE__ */ jsx4(View4, { style: styles4.badge, children: /* @__PURE__ */ jsx4(Text4, { style: styles4.badgeText, children: snap.unread }) }) : null
|
|
3091
3422
|
] });
|
|
@@ -3095,9 +3426,9 @@ function MessengerSheet({ store, client, palette: p, topInset, bottomInset }) {
|
|
|
3095
3426
|
const keyboard = useKeyboardHeight();
|
|
3096
3427
|
const v = snap.view;
|
|
3097
3428
|
const title = v.kind === "thread" ? snap.thread?.conversation?.subject || "New conversation" : v.kind === "article" ? "" : v.tab === "home" ? snap.config.name : v.tab === "messages" ? "Messages" : "Help";
|
|
3098
|
-
return /* @__PURE__ */ jsx4(
|
|
3429
|
+
return /* @__PURE__ */ jsx4(Modal2, { visible: snap.open, animationType: "slide", presentationStyle: Platform2.OS === "ios" ? "pageSheet" : "fullScreen", onRequestClose: () => v.kind === "tab" ? store.close() : store.back(), children: /* @__PURE__ */ jsxs3(View4, { style: [styles4.sheet, { backgroundColor: p.background, paddingTop: Platform2.OS === "ios" ? 8 : topInset, paddingBottom: keyboard }], children: [
|
|
3099
3430
|
/* @__PURE__ */ jsxs3(View4, { style: [styles4.header, { borderColor: p.border }], children: [
|
|
3100
|
-
v.kind !== "tab" ? /* @__PURE__ */ jsx4(
|
|
3431
|
+
v.kind !== "tab" ? /* @__PURE__ */ jsx4(Pressable4, { accessibilityRole: "button", accessibilityLabel: "Back", onPress: () => store.back(), hitSlop: 10, children: /* @__PURE__ */ jsx4(Text4, { style: [styles4.back, { color: p.primary }], children: "\u2039 Back" }) }) : null,
|
|
3101
3432
|
/* @__PURE__ */ jsx4(Text4, { accessibilityRole: "header", numberOfLines: 1, style: [styles4.title, { color: p.text, fontFamily: p.fontFamily }], children: title }),
|
|
3102
3433
|
/* @__PURE__ */ jsx4(CloseButton, { palette: p, onPress: () => store.close(), label: `Close ${snap.config.name}` })
|
|
3103
3434
|
] }),
|
|
@@ -3114,7 +3445,7 @@ function Tabs({ store, active, palette: p, bottomInset }) {
|
|
|
3114
3445
|
];
|
|
3115
3446
|
return /* @__PURE__ */ jsx4(View4, { accessibilityRole: "tablist", style: [styles4.tabs, { borderColor: p.border, paddingBottom: Math.max(8, bottomInset) }], children: tabs.map(([tab, icon, label]) => {
|
|
3116
3447
|
const on = tab === active;
|
|
3117
|
-
return /* @__PURE__ */ jsxs3(
|
|
3448
|
+
return /* @__PURE__ */ jsxs3(Pressable4, { accessibilityRole: "tab", accessibilityState: { selected: on }, accessibilityLabel: tab === "messages" && unread ? `${label}, ${unread} unread` : label, onPress: () => store.setTab(tab), style: styles4.tab, children: [
|
|
3118
3449
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.tabIcon, { color: on ? p.primary : p.muted }], children: icon }),
|
|
3119
3450
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.tabLabel, { color: on ? p.primary : p.muted }], children: label }),
|
|
3120
3451
|
tab === "messages" && unread ? /* @__PURE__ */ jsx4(View4, { style: [styles4.dot, styles4.tabDot] }) : null
|
|
@@ -3124,8 +3455,8 @@ function Tabs({ store, active, palette: p, bottomInset }) {
|
|
|
3124
3455
|
function Home({ store, palette: p }) {
|
|
3125
3456
|
const snap = useMessenger(store);
|
|
3126
3457
|
const recent = snap.conversations[0];
|
|
3127
|
-
const [q, setQ] =
|
|
3128
|
-
return /* @__PURE__ */ jsxs3(
|
|
3458
|
+
const [q, setQ] = useState2("");
|
|
3459
|
+
return /* @__PURE__ */ jsxs3(ScrollView3, { contentContainerStyle: styles4.content, keyboardShouldPersistTaps: "handled", children: [
|
|
3129
3460
|
/* @__PURE__ */ jsxs3(View4, { style: [styles4.hero, { backgroundColor: p.primary, borderRadius: p.radius }], children: [
|
|
3130
3461
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.heroTitle, { color: p.onPrimary }], children: snap.config.greeting || `Hi! I'm ${snap.config.name}.` }),
|
|
3131
3462
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.heroSub, { color: p.onPrimary }], children: snap.config.aiAvailable ? `${snap.config.name} answers right away${snap.config.handoffEnabled ? ", and the team is here when you need a person" : ""}.` : "The team usually replies within a few hours." })
|
|
@@ -3158,7 +3489,7 @@ function Home({ store, palette: p }) {
|
|
|
3158
3489
|
}
|
|
3159
3490
|
var pendingSearch = { current: "" };
|
|
3160
3491
|
function ConversationRow({ c, palette: p, onPress }) {
|
|
3161
|
-
return /* @__PURE__ */ jsxs3(
|
|
3492
|
+
return /* @__PURE__ */ jsxs3(Pressable4, { accessibilityRole: "button", accessibilityLabel: `${c.subject || "Conversation"}${c.unread ? ", unread" : ""}`, onPress, style: ({ pressed }) => [styles4.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3162
3493
|
/* @__PURE__ */ jsxs3(View4, { style: styles4.flex, children: [
|
|
3163
3494
|
/* @__PURE__ */ jsx4(Text4, { numberOfLines: 1, style: [styles4.rowTitle, { color: p.text }], children: c.subject || "Conversation" }),
|
|
3164
3495
|
/* @__PURE__ */ jsx4(Text4, { numberOfLines: 1, style: [styles4.rowSub, { color: p.muted }], children: c.lastMessagePreview || (c.status === "closed" ? "Closed" : " ") })
|
|
@@ -3171,7 +3502,7 @@ function ConversationRow({ c, palette: p, onPress }) {
|
|
|
3171
3502
|
}
|
|
3172
3503
|
function Conversations({ store, palette: p }) {
|
|
3173
3504
|
const snap = useMessenger(store);
|
|
3174
|
-
return /* @__PURE__ */ jsxs3(
|
|
3505
|
+
return /* @__PURE__ */ jsxs3(ScrollView3, { contentContainerStyle: styles4.content, children: [
|
|
3175
3506
|
snap.conversations.length ? snap.conversations.map((c) => /* @__PURE__ */ jsx4(ConversationRow, { c, palette: p, onPress: () => void store.openConversation(c.id) }, c.id)) : /* @__PURE__ */ jsx4(Text4, { style: [styles4.empty, { color: p.muted }], children: "No conversations yet." }),
|
|
3176
3507
|
/* @__PURE__ */ jsx4(GButton, { label: "New conversation", palette: p, onPress: () => store.showNewMessage(), style: styles4.fullWidth })
|
|
3177
3508
|
] });
|
|
@@ -3184,11 +3515,11 @@ function Bubble({ m, text, name, palette: p, onArticle, onGuide }) {
|
|
|
3184
3515
|
!mine ? /* @__PURE__ */ jsx4(Text4, { style: [styles4.author, { color: p.muted }], children: m.author === "agent" ? m.authorName || "Team" : name }) : null,
|
|
3185
3516
|
/* @__PURE__ */ jsx4(View4, { style: [styles4.bubble, { borderRadius: Math.max(12, p.radius) }, mine ? { backgroundColor: p.primary } : { backgroundColor: p.surface }], children: m.status === "pending" && !text ? /* @__PURE__ */ jsx4(TypingDots, { color: p.muted }) : /* @__PURE__ */ jsx4(Text4, { style: [styles4.bubbleText, { color: mine ? p.onPrimary : p.text }], children: text }) }),
|
|
3186
3517
|
m.citations.length || m.suggestedGuides.length ? /* @__PURE__ */ jsxs3(View4, { style: styles4.chips, children: [
|
|
3187
|
-
m.citations.map((c) => /* @__PURE__ */ jsx4(
|
|
3518
|
+
m.citations.map((c) => /* @__PURE__ */ jsx4(Pressable4, { accessibilityRole: "link", accessibilityLabel: `Article: ${c.title}`, onPress: () => onArticle(c.articleId), style: [styles4.chip, { borderColor: p.border }], children: /* @__PURE__ */ jsxs3(Text4, { style: [styles4.chipText, { color: p.text }], children: [
|
|
3188
3519
|
"\u{1F4C4} ",
|
|
3189
3520
|
c.title
|
|
3190
3521
|
] }) }, c.articleId)),
|
|
3191
|
-
m.suggestedGuides.map((g) => /* @__PURE__ */ jsx4(
|
|
3522
|
+
m.suggestedGuides.map((g) => /* @__PURE__ */ jsx4(Pressable4, { accessibilityRole: "button", accessibilityLabel: `Show me: ${g.name}`, onPress: () => onGuide(g.key), style: [styles4.chip, { borderColor: p.primary }], children: /* @__PURE__ */ jsxs3(Text4, { style: [styles4.chipText, { color: p.primary }], children: [
|
|
3192
3523
|
"\u25B6 Show me: ",
|
|
3193
3524
|
g.name
|
|
3194
3525
|
] }) }, g.key))
|
|
@@ -3201,10 +3532,10 @@ function TypingDots({ color }) {
|
|
|
3201
3532
|
function Thread({ store, palette: p, bottomInset }) {
|
|
3202
3533
|
const snap = useMessenger(store);
|
|
3203
3534
|
const t = snap.thread;
|
|
3204
|
-
const [text, setText] =
|
|
3535
|
+
const [text, setText] = useState2(t?.draft ?? "");
|
|
3205
3536
|
const scroll = useRef(null);
|
|
3206
3537
|
const convo = t?.conversation ?? null;
|
|
3207
|
-
|
|
3538
|
+
useEffect2(() => {
|
|
3208
3539
|
if (t?.draft) setText(t.draft);
|
|
3209
3540
|
}, [t?.draft]);
|
|
3210
3541
|
const streamingIds = useMemo2(() => Object.keys(t?.streaming ?? {}).filter((id) => !t?.messages.some((m) => m.id === id)), [t]);
|
|
@@ -3216,7 +3547,7 @@ function Thread({ store, palette: p, bottomInset }) {
|
|
|
3216
3547
|
};
|
|
3217
3548
|
const canHandoff = snap.config.handoffEnabled && snap.config.aiAvailable && convo?.status === "bot" && !t.sending;
|
|
3218
3549
|
return /* @__PURE__ */ jsxs3(View4, { style: styles4.flex, children: [
|
|
3219
|
-
/* @__PURE__ */ jsxs3(
|
|
3550
|
+
/* @__PURE__ */ jsxs3(ScrollView3, { ref: scroll, contentContainerStyle: styles4.thread, onContentSizeChange: () => scroll.current?.scrollToEnd({ animated: true }), keyboardShouldPersistTaps: "handled", children: [
|
|
3220
3551
|
!t.messages.length && !t.sending ? /* @__PURE__ */ jsx4(Text4, { style: [styles4.empty, { color: p.muted }], children: snap.config.greeting || "Ask us anything." }) : null,
|
|
3221
3552
|
t.messages.map((m) => /* @__PURE__ */ jsx4(Bubble, { m, text: t.streaming[m.id] ?? m.body, name: snap.config.name, palette: p, onArticle: (id) => void store.openArticle(id), onGuide: (k) => store.startGuide(k) }, m.id)),
|
|
3222
3553
|
streamingIds.map((id) => /* @__PURE__ */ jsx4(Bubble, { m: { id, author: "scout", body: "", citations: [], suggestedGuides: [], status: "pending", createdAt: (/* @__PURE__ */ new Date()).toISOString() }, text: t.streaming[id] ?? "", name: snap.config.name, palette: p, onArticle: () => {
|
|
@@ -3248,19 +3579,19 @@ function Thread({ store, palette: p, bottomInset }) {
|
|
|
3248
3579
|
function Rating({ palette: p, onRate }) {
|
|
3249
3580
|
return /* @__PURE__ */ jsxs3(View4, { style: styles4.rating, children: [
|
|
3250
3581
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.ratingTitle, { color: p.text }], children: "How did we do?" }),
|
|
3251
|
-
/* @__PURE__ */ jsx4(View4, { accessibilityRole: "radiogroup", style: styles4.stars, children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx4(
|
|
3582
|
+
/* @__PURE__ */ jsx4(View4, { accessibilityRole: "radiogroup", style: styles4.stars, children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx4(Pressable4, { accessibilityRole: "radio", accessibilityLabel: `${n} of 5`, onPress: () => onRate(n), hitSlop: 6, children: /* @__PURE__ */ jsx4(Text4, { style: [styles4.star, { color: p.primary }], children: "\u2605" }) }, n)) })
|
|
3252
3583
|
] });
|
|
3253
3584
|
}
|
|
3254
3585
|
function Help({ store, client, palette: p }) {
|
|
3255
3586
|
const snap = useMessenger(store);
|
|
3256
3587
|
const rc = client.getResourceCenter();
|
|
3257
|
-
const [q, setQ] =
|
|
3258
|
-
const [results, setResults] =
|
|
3259
|
-
const [faq, setFaq] =
|
|
3260
|
-
|
|
3588
|
+
const [q, setQ] = useState2(pendingSearch.current);
|
|
3589
|
+
const [results, setResults] = useState2(null);
|
|
3590
|
+
const [faq, setFaq] = useState2(null);
|
|
3591
|
+
useEffect2(() => {
|
|
3261
3592
|
pendingSearch.current = "";
|
|
3262
3593
|
}, []);
|
|
3263
|
-
|
|
3594
|
+
useEffect2(() => {
|
|
3264
3595
|
const query = q.trim();
|
|
3265
3596
|
if (query.length < 2) return setResults(null);
|
|
3266
3597
|
let alive = true;
|
|
@@ -3273,7 +3604,7 @@ function Help({ store, client, palette: p }) {
|
|
|
3273
3604
|
const guides = client.getGuides();
|
|
3274
3605
|
const recommended = (rc?.recommendedGuideIds ?? []).map((id) => guides.find((g) => g.id === id || g.key === id)).filter((g) => !!g);
|
|
3275
3606
|
const articles = snap.articles;
|
|
3276
|
-
const row = (key, title, sub, onPress, icon = "\u203A") => /* @__PURE__ */ jsxs3(
|
|
3607
|
+
const row = (key, title, sub, onPress, icon = "\u203A") => /* @__PURE__ */ jsxs3(Pressable4, { accessibilityRole: "button", accessibilityLabel: title, onPress, style: ({ pressed }) => [styles4.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3277
3608
|
/* @__PURE__ */ jsxs3(View4, { style: styles4.flex, children: [
|
|
3278
3609
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.rowTitle, { color: p.text }], children: title }),
|
|
3279
3610
|
sub ? /* @__PURE__ */ jsx4(Text4, { numberOfLines: 2, style: [styles4.rowSub, { color: p.muted }], children: sub }) : null
|
|
@@ -3285,22 +3616,19 @@ function Help({ store, client, palette: p }) {
|
|
|
3285
3616
|
/* @__PURE__ */ jsx4(Text4, { accessibilityRole: "header", style: [styles4.sectionTitle, { color: p.muted }], children: title.toUpperCase() }),
|
|
3286
3617
|
children
|
|
3287
3618
|
] }, title);
|
|
3288
|
-
const
|
|
3289
|
-
const
|
|
3290
|
-
|
|
3619
|
+
const audiences = client.getAudienceIds();
|
|
3620
|
+
const sections = resourceCenterSections(articles?.collections ?? [], articles?.articles ?? [], audiences);
|
|
3621
|
+
const listed = results?.filter((a) => isArticleListed(articles?.collections ?? [], a, audiences));
|
|
3622
|
+
return /* @__PURE__ */ jsxs3(ScrollView3, { contentContainerStyle: styles4.content, keyboardShouldPersistTaps: "handled", children: [
|
|
3291
3623
|
/* @__PURE__ */ jsx4(TextInput, { value: q, onChangeText: setQ, placeholder: "Search articles", placeholderTextColor: p.muted, accessibilityLabel: "Search help articles", returnKeyType: "search", style: [styles4.search, { color: p.text, backgroundColor: p.surface, borderRadius: Math.min(10, p.radius) }] }),
|
|
3292
|
-
|
|
3624
|
+
listed ? section(`Results for \u201C${q.trim()}\u201D`, listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => open(a))) : /* @__PURE__ */ jsx4(Text4, { style: [styles4.rowSub, { color: p.muted }], children: "No articles found." })) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
3293
3625
|
recommended.length ? section("Recommended", recommended.map((g) => row(g.id, g.name, void 0, () => store.startGuide(g.key), "\u25B6"))) : null,
|
|
3294
3626
|
!articles ? /* @__PURE__ */ jsx4(ActivityIndicator, { color: p.muted }) : null,
|
|
3295
|
-
|
|
3296
|
-
const items = (articles?.articles ?? []).filter((a) => a.collectionId === c.id);
|
|
3297
|
-
return items.length ? section(c.name, items.map((a) => row(a.id, a.title, a.summary, () => open(a)))) : null;
|
|
3298
|
-
}),
|
|
3299
|
-
loose.length ? section("Articles", loose.map((a) => row(a.id, a.title, a.summary, () => open(a)))) : null,
|
|
3627
|
+
sections.map((s) => section(s.collection ? s.path.join(" \u203A ") : "Articles", s.articles.map((a) => row(a.id, a.title, a.summary, () => open(a))))),
|
|
3300
3628
|
rc?.faqs.length ? section(
|
|
3301
3629
|
"FAQ",
|
|
3302
3630
|
rc.faqs.map((f) => /* @__PURE__ */ jsxs3(View4, { style: [styles4.row, styles4.faq, { borderColor: p.border }], children: [
|
|
3303
|
-
/* @__PURE__ */ jsxs3(
|
|
3631
|
+
/* @__PURE__ */ jsxs3(Pressable4, { accessibilityRole: "button", accessibilityState: { expanded: faq === f.id }, onPress: () => setFaq(faq === f.id ? null : f.id), style: styles4.faqHead, children: [
|
|
3304
3632
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.rowTitle, styles4.flex, { color: p.text }], children: f.question }),
|
|
3305
3633
|
/* @__PURE__ */ jsx4(Text4, { style: [styles4.chev, { color: p.muted }], children: faq === f.id ? "\u2212" : "+" })
|
|
3306
3634
|
] }),
|
|
@@ -3313,7 +3641,7 @@ function Help({ store, client, palette: p }) {
|
|
|
3313
3641
|
}
|
|
3314
3642
|
function Article({ article, palette: p, client }) {
|
|
3315
3643
|
if (!article) return /* @__PURE__ */ jsx4(ActivityIndicator, { style: styles4.loading, color: p.muted });
|
|
3316
|
-
return /* @__PURE__ */ jsxs3(
|
|
3644
|
+
return /* @__PURE__ */ jsxs3(ScrollView3, { contentContainerStyle: styles4.content, children: [
|
|
3317
3645
|
/* @__PURE__ */ jsx4(Text4, { accessibilityRole: "header", style: [styles4.articleTitle, { color: p.text, fontFamily: p.fontFamily }], children: article.title }),
|
|
3318
3646
|
/* @__PURE__ */ jsx4(RichText, { html: article.body, palette: p, onLink: (u) => client.navigate(u) })
|
|
3319
3647
|
] });
|
|
@@ -3375,23 +3703,23 @@ var styles4 = StyleSheet4.create({
|
|
|
3375
3703
|
});
|
|
3376
3704
|
|
|
3377
3705
|
// src/ui/ResourceCenter.tsx
|
|
3378
|
-
import { useEffect as
|
|
3379
|
-
import { Modal as
|
|
3706
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
|
|
3707
|
+
import { Modal as Modal3, Platform as Platform3, Pressable as Pressable5, ScrollView as ScrollView4, StyleSheet as StyleSheet5, Text as Text5, TextInput as TextInput2, View as View5 } from "react-native";
|
|
3380
3708
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3381
3709
|
function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
3382
3710
|
const rc = client.getResourceCenter();
|
|
3383
|
-
const [query, setQuery] =
|
|
3384
|
-
const [results, setResults] =
|
|
3385
|
-
const [article, setArticle] =
|
|
3386
|
-
const [faq, setFaq] =
|
|
3387
|
-
|
|
3711
|
+
const [query, setQuery] = useState3("");
|
|
3712
|
+
const [results, setResults] = useState3(null);
|
|
3713
|
+
const [article, setArticle] = useState3(null);
|
|
3714
|
+
const [faq, setFaq] = useState3(null);
|
|
3715
|
+
useEffect3(() => {
|
|
3388
3716
|
if (!open) {
|
|
3389
3717
|
setQuery("");
|
|
3390
3718
|
setResults(null);
|
|
3391
3719
|
setArticle(null);
|
|
3392
3720
|
}
|
|
3393
3721
|
}, [open]);
|
|
3394
|
-
|
|
3722
|
+
useEffect3(() => {
|
|
3395
3723
|
const q = query.trim();
|
|
3396
3724
|
if (q.length < 2) {
|
|
3397
3725
|
setResults(null);
|
|
@@ -3416,7 +3744,7 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3416
3744
|
client.articleViewed(a);
|
|
3417
3745
|
setArticle(a);
|
|
3418
3746
|
};
|
|
3419
|
-
const row = (key, title, subtitle, onPress, icon = "\u203A") => /* @__PURE__ */ jsxs4(
|
|
3747
|
+
const row = (key, title, subtitle, onPress, icon = "\u203A") => /* @__PURE__ */ jsxs4(Pressable5, { accessibilityRole: "button", accessibilityLabel: title, onPress, style: ({ pressed }) => [styles5.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3420
3748
|
/* @__PURE__ */ jsxs4(View5, { style: styles5.flex, children: [
|
|
3421
3749
|
/* @__PURE__ */ jsx5(Text5, { style: [styles5.rowTitle, { color: p.text, fontFamily: p.fontFamily }], children: title }),
|
|
3422
3750
|
subtitle ? /* @__PURE__ */ jsx5(Text5, { style: [styles5.rowSub, { color: p.muted }], numberOfLines: 2, children: subtitle }) : null
|
|
@@ -3427,18 +3755,19 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3427
3755
|
/* @__PURE__ */ jsx5(Text5, { accessibilityRole: "header", style: [styles5.sectionTitle, { color: p.muted }], children: title.toUpperCase() }),
|
|
3428
3756
|
children
|
|
3429
3757
|
] }, title);
|
|
3430
|
-
const
|
|
3431
|
-
const
|
|
3432
|
-
|
|
3758
|
+
const audiences = client.getAudienceIds();
|
|
3759
|
+
const sections = resourceCenterSections(rc.collections, rc.articles, audiences);
|
|
3760
|
+
const listed = results?.filter((a) => isArticleListed(rc.collections, a, audiences));
|
|
3761
|
+
return /* @__PURE__ */ jsx5(Modal3, { visible: open, animationType: "slide", presentationStyle: Platform3.OS === "ios" ? "pageSheet" : "fullScreen", onRequestClose: () => article ? setArticle(null) : close(), children: /* @__PURE__ */ jsxs4(View5, { style: [styles5.sheet, { backgroundColor: p.background, paddingTop: Platform3.OS === "ios" ? 8 : topInset }], children: [
|
|
3433
3762
|
/* @__PURE__ */ jsxs4(View5, { style: [styles5.header, { borderColor: p.border }], children: [
|
|
3434
|
-
article ? /* @__PURE__ */ jsx5(
|
|
3763
|
+
article ? /* @__PURE__ */ jsx5(Pressable5, { accessibilityRole: "button", accessibilityLabel: "Back", onPress: () => setArticle(null), hitSlop: 10, children: /* @__PURE__ */ jsx5(Text5, { style: [styles5.back, { color: p.primary }], children: "\u2039 Back" }) }) : null,
|
|
3435
3764
|
/* @__PURE__ */ jsx5(Text5, { accessibilityRole: "header", style: [styles5.title, { color: p.text, fontFamily: p.fontFamily }], numberOfLines: 1, children: article ? "" : rc.title }),
|
|
3436
3765
|
/* @__PURE__ */ jsx5(CloseButton, { palette: p, onPress: close, label: "Close help" })
|
|
3437
3766
|
] }),
|
|
3438
|
-
article ? /* @__PURE__ */ jsxs4(
|
|
3767
|
+
article ? /* @__PURE__ */ jsxs4(ScrollView4, { contentContainerStyle: [styles5.content, { paddingBottom: bottomInset + 24 }], children: [
|
|
3439
3768
|
/* @__PURE__ */ jsx5(Text5, { accessibilityRole: "header", style: [styles5.articleTitle, { color: p.text, fontFamily: p.fontFamily }], children: article.title }),
|
|
3440
3769
|
/* @__PURE__ */ jsx5(RichText, { html: article.body, palette: p, onLink: (u) => client.navigate(u) })
|
|
3441
|
-
] }) : /* @__PURE__ */ jsxs4(
|
|
3770
|
+
] }) : /* @__PURE__ */ jsxs4(ScrollView4, { contentContainerStyle: [styles5.content, { paddingBottom: bottomInset + 24 }], keyboardShouldPersistTaps: "handled", children: [
|
|
3442
3771
|
/* @__PURE__ */ jsx5(
|
|
3443
3772
|
TextInput2,
|
|
3444
3773
|
{
|
|
@@ -3452,21 +3781,17 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3452
3781
|
style: [styles5.search, { color: p.text, backgroundColor: p.surface, borderRadius: Math.min(10, p.radius) }]
|
|
3453
3782
|
}
|
|
3454
3783
|
),
|
|
3455
|
-
|
|
3784
|
+
listed ? section(
|
|
3456
3785
|
`Results for \u201C${query.trim()}\u201D`,
|
|
3457
|
-
|
|
3786
|
+
listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => openArticle(a))) : /* @__PURE__ */ jsx5(Text5, { style: [styles5.rowSub, { color: p.muted }], children: "No articles found." })
|
|
3458
3787
|
) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3459
3788
|
recommended.length ? section("Recommended", recommended.map((g) => row(g.id, g.name, void 0, () => (close(), client.startGuide(g.id)), "\u25B6"))) : null,
|
|
3460
3789
|
checklists.length ? section("Checklists", checklists.map((g) => row(g.id, g.name, void 0, () => (close(), client.openChecklist(g.id)), "\u2611"))) : null,
|
|
3461
|
-
|
|
3462
|
-
const items = rc.articles.filter((a) => a.collectionId === c.id);
|
|
3463
|
-
return items.length ? section(c.name, items.map((a) => row(a.id, a.title, a.summary, () => openArticle(a)))) : null;
|
|
3464
|
-
}),
|
|
3465
|
-
loose.length ? section("Articles", loose.map((a) => row(a.id, a.title, a.summary, () => openArticle(a)))) : null,
|
|
3790
|
+
sections.map((s) => section(s.collection ? s.path.join(" \u203A ") : "Articles", s.articles.map((a) => row(a.id, a.title, a.summary, () => openArticle(a))))),
|
|
3466
3791
|
rc.faqs.length ? section(
|
|
3467
3792
|
"FAQ",
|
|
3468
3793
|
rc.faqs.map((f) => /* @__PURE__ */ jsxs4(View5, { style: [styles5.row, styles5.faq, { borderColor: p.border }], children: [
|
|
3469
|
-
/* @__PURE__ */ jsxs4(
|
|
3794
|
+
/* @__PURE__ */ jsxs4(Pressable5, { accessibilityRole: "button", accessibilityState: { expanded: faq === f.id }, onPress: () => setFaq(faq === f.id ? null : f.id), style: styles5.faqHead, children: [
|
|
3470
3795
|
/* @__PURE__ */ jsx5(Text5, { style: [styles5.rowTitle, styles5.flex, { color: p.text }], children: f.question }),
|
|
3471
3796
|
/* @__PURE__ */ jsx5(Text5, { style: [styles5.chev, { color: p.muted }], children: faq === f.id ? "\u2212" : "+" })
|
|
3472
3797
|
] }),
|
|
@@ -3498,8 +3823,8 @@ var styles5 = StyleSheet5.create({
|
|
|
3498
3823
|
});
|
|
3499
3824
|
|
|
3500
3825
|
// src/ui/StepLayer.tsx
|
|
3501
|
-
import { useEffect as
|
|
3502
|
-
import { AccessibilityInfo, Animated, Easing, Pressable as
|
|
3826
|
+
import { useEffect as useEffect4, useRef as useRef2, useState as useState4 } from "react";
|
|
3827
|
+
import { AccessibilityInfo, Animated, Easing, Pressable as Pressable6, StyleSheet as StyleSheet7, View as View7 } from "react-native";
|
|
3503
3828
|
|
|
3504
3829
|
// src/core/position.ts
|
|
3505
3830
|
var MARGIN = 12;
|
|
@@ -3539,7 +3864,7 @@ function positionCard(target, size, viewport, insets, placement, offset) {
|
|
|
3539
3864
|
}
|
|
3540
3865
|
|
|
3541
3866
|
// src/ui/StepCard.tsx
|
|
3542
|
-
import { Image, StyleSheet as StyleSheet6, Text as Text6, View as View6 } from "react-native";
|
|
3867
|
+
import { Image as Image2, StyleSheet as StyleSheet6, Text as Text6, View as View6 } from "react-native";
|
|
3543
3868
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3544
3869
|
function StepCard({ view, client, palette: p, width, style, compact }) {
|
|
3545
3870
|
const { step, guide } = view;
|
|
@@ -3548,7 +3873,7 @@ function StepCard({ view, client, palette: p, width, style, compact }) {
|
|
|
3548
3873
|
const showProgress = step.showProgress && view.total > 1;
|
|
3549
3874
|
const onLink = (url) => client.navigate(url);
|
|
3550
3875
|
return /* @__PURE__ */ jsx6(Surface, { palette: p, style: [{ width }, style], children: /* @__PURE__ */ jsxs5(View6, { accessible: false, accessibilityViewIsModal: view.asModal || step.type === "modal", style: compact ? styles6.compact : styles6.inner, children: [
|
|
3551
|
-
step.imageUrl ? /* @__PURE__ */ jsx6(
|
|
3876
|
+
step.imageUrl ? /* @__PURE__ */ jsx6(Image2, { source: { uri: step.imageUrl }, style: [styles6.image, { borderRadius: Math.max(0, p.radius - 4) }], resizeMode: "cover", accessibilityIgnoresInvertColors: true }) : null,
|
|
3552
3877
|
step.title ? /* @__PURE__ */ jsxs5(View6, { style: styles6.header, children: [
|
|
3553
3878
|
/* @__PURE__ */ jsx6(Text6, { accessibilityRole: "header", style: [styles6.title, { color: p.text, fontFamily: p.fontFamily }], children: step.title }),
|
|
3554
3879
|
step.showClose ? /* @__PURE__ */ jsx6(CloseButton, { palette: p, onPress: () => client.closeStep(guide.id), label: "Dismiss guide" }) : null
|
|
@@ -3591,8 +3916,8 @@ var styles6 = StyleSheet6.create({
|
|
|
3591
3916
|
// src/ui/StepLayer.tsx
|
|
3592
3917
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3593
3918
|
function useTargetRect(client, targetId, origin) {
|
|
3594
|
-
const [rect, setRect] =
|
|
3595
|
-
|
|
3919
|
+
const [rect, setRect] = useState4(null);
|
|
3920
|
+
useEffect4(() => {
|
|
3596
3921
|
if (!targetId) {
|
|
3597
3922
|
setRect(null);
|
|
3598
3923
|
return;
|
|
@@ -3620,7 +3945,7 @@ function useTargetRect(client, targetId, origin) {
|
|
|
3620
3945
|
}
|
|
3621
3946
|
function useFadeIn(key) {
|
|
3622
3947
|
const opacity = useRef2(new Animated.Value(0)).current;
|
|
3623
|
-
|
|
3948
|
+
useEffect4(() => {
|
|
3624
3949
|
opacity.setValue(0);
|
|
3625
3950
|
Animated.timing(opacity, { toValue: 1, duration: 160, easing: Easing.out(Easing.quad), useNativeDriver: true }).start();
|
|
3626
3951
|
}, [key, opacity]);
|
|
@@ -3632,11 +3957,11 @@ function StepLayer({ view, client, palette: p, geometry }) {
|
|
|
3632
3957
|
const opacity = useFadeIn(view.key);
|
|
3633
3958
|
const { viewport, insets } = geometry;
|
|
3634
3959
|
const cardWidth = Math.min(viewport.width - 32, step.width ?? 340);
|
|
3635
|
-
|
|
3960
|
+
useEffect4(() => {
|
|
3636
3961
|
if (step.type === "hotspot" && !view.expanded) return;
|
|
3637
3962
|
AccessibilityInfo.announceForAccessibility?.(announcement(view));
|
|
3638
3963
|
}, [view.key, view.expanded]);
|
|
3639
|
-
const backdrop = (children) => /* @__PURE__ */ jsx7(
|
|
3964
|
+
const backdrop = (children) => /* @__PURE__ */ jsx7(Pressable6, { accessible: false, style: [StyleSheet7.absoluteFill, { backgroundColor: p.overlay }], onPress: () => client.backdropPressed(view.guide.id), children });
|
|
3640
3965
|
const anchored = !view.asModal && ["tooltip", "popover", "spotlight", "hotspot"].includes(step.type);
|
|
3641
3966
|
if (!anchored && step.type === "banner") {
|
|
3642
3967
|
const top = step.position.startsWith("top");
|
|
@@ -3675,10 +4000,10 @@ function StepLayer({ view, client, palette: p, geometry }) {
|
|
|
3675
4000
|
[hole.x + hole.width - r, hole.y + hole.height - r, -2 * r, -2 * r]
|
|
3676
4001
|
];
|
|
3677
4002
|
return /* @__PURE__ */ jsxs6(Animated.View, { pointerEvents: "box-none", style: [StyleSheet7.absoluteFill, { opacity }], children: [
|
|
3678
|
-
/* @__PURE__ */ jsx7(
|
|
3679
|
-
/* @__PURE__ */ jsx7(
|
|
3680
|
-
/* @__PURE__ */ jsx7(
|
|
3681
|
-
/* @__PURE__ */ jsx7(
|
|
4003
|
+
/* @__PURE__ */ jsx7(Pressable6, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, right: 0, top: 0, height: Math.max(0, hole.y) }] }),
|
|
4004
|
+
/* @__PURE__ */ jsx7(Pressable6, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, right: 0, top: hole.y + hole.height, bottom: 0 }] }),
|
|
4005
|
+
/* @__PURE__ */ jsx7(Pressable6, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, width: Math.max(0, hole.x), top: hole.y, height: hole.height }] }),
|
|
4006
|
+
/* @__PURE__ */ jsx7(Pressable6, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: hole.x + hole.width, right: 0, top: hole.y, height: hole.height }] }),
|
|
3682
4007
|
r > 0 ? corners.map(([left, top, dx, dy], i) => /* @__PURE__ */ jsx7(View7, { pointerEvents: "none", style: [styles7.abs, { left, top, width: r, height: r, overflow: "hidden" }], children: /* @__PURE__ */ jsx7(View7, { style: [styles7.abs, { left: dx, top: dy, width: 4 * r, height: 4 * r, borderRadius: 2 * r, borderWidth: r, borderColor: p.overlay }] }) }, i)) : null,
|
|
3683
4008
|
/* @__PURE__ */ jsx7(View7, { pointerEvents: "none", style: [styles7.abs, { left: hole.x, top: hole.y, width: hole.width, height: hole.height, borderRadius: r, borderWidth: 2, borderColor: p.primary }] }),
|
|
3684
4009
|
/* @__PURE__ */ jsx7(Anchored, { view, client, palette: p, geometry, rect: hole, width: cardWidth })
|
|
@@ -3691,7 +4016,7 @@ function StepLayer({ view, client, palette: p, geometry }) {
|
|
|
3691
4016
|
}
|
|
3692
4017
|
var ARROW = 12;
|
|
3693
4018
|
function Anchored({ view, client, palette: p, geometry, rect, width }) {
|
|
3694
|
-
const [height, setHeight] =
|
|
4019
|
+
const [height, setHeight] = useState4(0);
|
|
3695
4020
|
const onLayout = (e) => setHeight(Math.round(e.nativeEvent.layout.height));
|
|
3696
4021
|
const offset = view.step.offset + ARROW / 2;
|
|
3697
4022
|
const pos = positionCard(rect, { width, height: height || 120 }, geometry.viewport, geometry.insets, view.step.placement, offset);
|
|
@@ -3707,8 +4032,8 @@ function Arrow({ side, at, color, border }) {
|
|
|
3707
4032
|
}
|
|
3708
4033
|
function Hotspot({ x, y, size, pulse, color, onPress, label }) {
|
|
3709
4034
|
const scale = useRef2(new Animated.Value(0)).current;
|
|
3710
|
-
const [reduceMotion, setReduceMotion] =
|
|
3711
|
-
|
|
4035
|
+
const [reduceMotion, setReduceMotion] = useState4(false);
|
|
4036
|
+
useEffect4(() => {
|
|
3712
4037
|
let alive = true;
|
|
3713
4038
|
AccessibilityInfo.isReduceMotionEnabled?.().then((v) => alive && setReduceMotion(v), () => {
|
|
3714
4039
|
});
|
|
@@ -3716,13 +4041,13 @@ function Hotspot({ x, y, size, pulse, color, onPress, label }) {
|
|
|
3716
4041
|
alive = false;
|
|
3717
4042
|
};
|
|
3718
4043
|
}, []);
|
|
3719
|
-
|
|
4044
|
+
useEffect4(() => {
|
|
3720
4045
|
if (!pulse || reduceMotion) return;
|
|
3721
4046
|
const loop = Animated.loop(Animated.timing(scale, { toValue: 1, duration: 1400, easing: Easing.out(Easing.ease), useNativeDriver: true }));
|
|
3722
4047
|
loop.start();
|
|
3723
4048
|
return () => loop.stop();
|
|
3724
4049
|
}, [pulse, reduceMotion, scale]);
|
|
3725
|
-
return /* @__PURE__ */ jsxs6(
|
|
4050
|
+
return /* @__PURE__ */ jsxs6(Pressable6, { accessibilityRole: "button", accessibilityLabel: label, onPress, hitSlop: 14, style: [styles7.abs, { left: x, top: y, width: size, height: size }], children: [
|
|
3726
4051
|
pulse && !reduceMotion ? /* @__PURE__ */ jsx7(
|
|
3727
4052
|
Animated.View,
|
|
3728
4053
|
{
|
|
@@ -3741,13 +4066,13 @@ var styles7 = StyleSheet7.create({
|
|
|
3741
4066
|
});
|
|
3742
4067
|
|
|
3743
4068
|
// src/ui/Survey.tsx
|
|
3744
|
-
import { useEffect as
|
|
4069
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
3745
4070
|
import {
|
|
3746
4071
|
AccessibilityInfo as AccessibilityInfo2,
|
|
3747
4072
|
KeyboardAvoidingView,
|
|
3748
4073
|
Platform as Platform4,
|
|
3749
|
-
Pressable as
|
|
3750
|
-
ScrollView as
|
|
4074
|
+
Pressable as Pressable7,
|
|
4075
|
+
ScrollView as ScrollView5,
|
|
3751
4076
|
StyleSheet as StyleSheet8,
|
|
3752
4077
|
Text as Text7,
|
|
3753
4078
|
TextInput as TextInput3,
|
|
@@ -3761,9 +4086,9 @@ function Survey({
|
|
|
3761
4086
|
geometry
|
|
3762
4087
|
}) {
|
|
3763
4088
|
const config = view.guide.config.survey;
|
|
3764
|
-
const [answers, setAnswers] =
|
|
3765
|
-
const [error, setError] =
|
|
3766
|
-
|
|
4089
|
+
const [answers, setAnswers] = useState5({});
|
|
4090
|
+
const [error, setError] = useState5("");
|
|
4091
|
+
useEffect5(() => {
|
|
3767
4092
|
setAnswers({});
|
|
3768
4093
|
setError("");
|
|
3769
4094
|
AccessibilityInfo2.announceForAccessibility?.(
|
|
@@ -3804,7 +4129,7 @@ function Survey({
|
|
|
3804
4129
|
style: StyleSheet8.absoluteFill,
|
|
3805
4130
|
children: [
|
|
3806
4131
|
centered ? /* @__PURE__ */ jsx8(
|
|
3807
|
-
|
|
4132
|
+
Pressable7,
|
|
3808
4133
|
{
|
|
3809
4134
|
accessible: false,
|
|
3810
4135
|
style: [StyleSheet8.absoluteFill, { backgroundColor: p.overlay }],
|
|
@@ -3843,7 +4168,7 @@ function Survey({
|
|
|
3843
4168
|
}
|
|
3844
4169
|
) : null,
|
|
3845
4170
|
/* @__PURE__ */ jsx8(GButton, { label: "Done", palette: p, onPress: close, style: styles8.end })
|
|
3846
|
-
] }) : /* @__PURE__ */ jsxs7(
|
|
4171
|
+
] }) : /* @__PURE__ */ jsxs7(ScrollView5, { contentContainerStyle: styles8.inner, keyboardShouldPersistTaps: "handled", children: [
|
|
3847
4172
|
config.questions.filter((q) => isQuestionVisible(q, answers)).map((q, i) => /* @__PURE__ */ jsxs7(View8, { style: styles8.question, children: [
|
|
3848
4173
|
/* @__PURE__ */ jsxs7(View8, { style: styles8.head, children: [
|
|
3849
4174
|
/* @__PURE__ */ jsxs7(Text7, { style: [styles8.qTitle, { color: p.text, fontFamily: p.fontFamily }], children: [
|
|
@@ -3901,7 +4226,7 @@ function QuestionInput({
|
|
|
3901
4226
|
const values = Array.from({ length: max - min + 1 }, (_, i) => min + i);
|
|
3902
4227
|
return /* @__PURE__ */ jsxs7(View8, { children: [
|
|
3903
4228
|
/* @__PURE__ */ jsx8(View8, { style: styles8.scale, accessibilityRole: "radiogroup", accessibilityLabel: q.title, children: values.map((n) => /* @__PURE__ */ jsx8(
|
|
3904
|
-
|
|
4229
|
+
Pressable7,
|
|
3905
4230
|
{
|
|
3906
4231
|
accessibilityRole: "radio",
|
|
3907
4232
|
accessibilityState: { selected: value === n },
|
|
@@ -3921,7 +4246,7 @@ function QuestionInput({
|
|
|
3921
4246
|
case "rating": {
|
|
3922
4247
|
const max = q.scaleMax ?? 5;
|
|
3923
4248
|
return /* @__PURE__ */ jsx8(View8, { style: styles8.stars, accessibilityRole: "radiogroup", accessibilityLabel: q.title, children: Array.from({ length: max }, (_, i) => i + 1).map((n) => /* @__PURE__ */ jsx8(
|
|
3924
|
-
|
|
4249
|
+
Pressable7,
|
|
3925
4250
|
{
|
|
3926
4251
|
accessibilityRole: "radio",
|
|
3927
4252
|
accessibilityLabel: `${n} of ${max}`,
|
|
@@ -3947,7 +4272,7 @@ function QuestionInput({
|
|
|
3947
4272
|
[true, "\u{1F44D}", "Thumbs up"],
|
|
3948
4273
|
[false, "\u{1F44E}", "Thumbs down"]
|
|
3949
4274
|
].map(([val, icon, label]) => /* @__PURE__ */ jsx8(
|
|
3950
|
-
|
|
4275
|
+
Pressable7,
|
|
3951
4276
|
{
|
|
3952
4277
|
accessibilityRole: "radio",
|
|
3953
4278
|
accessibilityLabel: label,
|
|
@@ -3967,7 +4292,7 @@ function QuestionInput({
|
|
|
3967
4292
|
return /* @__PURE__ */ jsx8(View8, { style: styles8.choices, children: q.options.map((o) => {
|
|
3968
4293
|
const on = selected.has(o.id);
|
|
3969
4294
|
return /* @__PURE__ */ jsxs7(
|
|
3970
|
-
|
|
4295
|
+
Pressable7,
|
|
3971
4296
|
{
|
|
3972
4297
|
accessibilityRole: multi ? "checkbox" : "radio",
|
|
3973
4298
|
accessibilityState: { checked: on },
|
|
@@ -4132,8 +4457,8 @@ function GuidelyOverlay({ client, insets: insetsProp, launcherOffset }) {
|
|
|
4132
4457
|
const { width, height } = useWindowDimensions();
|
|
4133
4458
|
const scheme = useColorScheme();
|
|
4134
4459
|
const ref = useRef3(null);
|
|
4135
|
-
const [origin, setOrigin] =
|
|
4136
|
-
|
|
4460
|
+
const [origin, setOrigin] = useState6({ x: 0, y: 0 });
|
|
4461
|
+
useEffect6(() => {
|
|
4137
4462
|
client.targets.setViewport(width, height);
|
|
4138
4463
|
}, [client, width, height]);
|
|
4139
4464
|
const measureOrigin = useCallback2(() => {
|
|
@@ -4151,7 +4476,7 @@ function GuidelyOverlay({ client, insets: insetsProp, launcherOffset }) {
|
|
|
4151
4476
|
return /* @__PURE__ */ jsxs8(View9, { ref, collapsable: false, pointerEvents: "box-none", style: StyleSheet9.absoluteFill, onLayout: measureOrigin, children: [
|
|
4152
4477
|
ui.checklists.map((c) => /* @__PURE__ */ jsx9(Checklist, { view: c, client, palette: palette(client.themeFor(c.guide), scheme), geometry, showLauncher: client.options.showChecklistLauncher !== false, launcherBottom: launcherOffset }, c.guide.id)),
|
|
4153
4478
|
showRcLauncher ? /* @__PURE__ */ jsx9(
|
|
4154
|
-
|
|
4479
|
+
Pressable8,
|
|
4155
4480
|
{
|
|
4156
4481
|
accessibilityRole: "button",
|
|
4157
4482
|
accessibilityLabel: client.getResourceCenter()?.launcher.label || "Help",
|
|
@@ -4172,7 +4497,7 @@ var styles9 = StyleSheet9.create({
|
|
|
4172
4497
|
});
|
|
4173
4498
|
|
|
4174
4499
|
// src/ui/Target.tsx
|
|
4175
|
-
import { createContext, useCallback as useCallback3, useContext, useEffect as
|
|
4500
|
+
import { createContext, useCallback as useCallback3, useContext, useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
4176
4501
|
import { View as View10 } from "react-native";
|
|
4177
4502
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4178
4503
|
var GuidelyContext = createContext(null);
|
|
@@ -4189,7 +4514,7 @@ function useGuidelyTarget(id) {
|
|
|
4189
4514
|
const screen = useContext(GuidelyScreenContext);
|
|
4190
4515
|
const ref = useRef4(null);
|
|
4191
4516
|
const start = useRef4(null);
|
|
4192
|
-
|
|
4517
|
+
useEffect7(() => {
|
|
4193
4518
|
if (!client || !id) return;
|
|
4194
4519
|
return client.targets.register(id, {
|
|
4195
4520
|
screen,
|
|
@@ -4262,11 +4587,11 @@ function defaultBridge(appVersion) {
|
|
|
4262
4587
|
};
|
|
4263
4588
|
}
|
|
4264
4589
|
function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...options }) {
|
|
4265
|
-
const [client, setClient] =
|
|
4590
|
+
const [client, setClient] = useState7(null);
|
|
4266
4591
|
const optionsRef = useRef5(options);
|
|
4267
4592
|
optionsRef.current = options;
|
|
4268
4593
|
const { projectId, environment, apiUrl, storage } = options;
|
|
4269
|
-
|
|
4594
|
+
useEffect8(() => {
|
|
4270
4595
|
if (!projectId) return;
|
|
4271
4596
|
let c;
|
|
4272
4597
|
try {
|
|
@@ -4290,7 +4615,7 @@ function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...optio
|
|
|
4290
4615
|
}, [projectId, environment, apiUrl, storage]);
|
|
4291
4616
|
const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : "";
|
|
4292
4617
|
const hadUser = useRef5(false);
|
|
4293
|
-
|
|
4618
|
+
useEffect8(() => {
|
|
4294
4619
|
if (!client) return;
|
|
4295
4620
|
if (user && user.id) {
|
|
4296
4621
|
hadUser.current = true;
|
|
@@ -4339,8 +4664,8 @@ function useGuidely() {
|
|
|
4339
4664
|
}
|
|
4340
4665
|
function useGuidelyReady() {
|
|
4341
4666
|
const client = useContext2(GuidelyContext);
|
|
4342
|
-
const [ready, setReady] =
|
|
4343
|
-
|
|
4667
|
+
const [ready, setReady] = useState7(() => !!client?.isClientReady());
|
|
4668
|
+
useEffect8(() => {
|
|
4344
4669
|
if (!client) return setReady(false);
|
|
4345
4670
|
setReady(client.isClientReady());
|
|
4346
4671
|
const off = client.on("ready", () => setReady(true));
|
|
@@ -4352,7 +4677,7 @@ function useGuidelyReady() {
|
|
|
4352
4677
|
function useGuidelyIdentify(userId, traits, account) {
|
|
4353
4678
|
const client = useContext2(GuidelyContext);
|
|
4354
4679
|
const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);
|
|
4355
|
-
|
|
4680
|
+
useEffect8(() => {
|
|
4356
4681
|
if (client && userId) void client.identify(userId, traits, account);
|
|
4357
4682
|
}, [client, key]);
|
|
4358
4683
|
}
|
|
@@ -4360,14 +4685,14 @@ function useGuidelyEvent(event, handler) {
|
|
|
4360
4685
|
const client = useContext2(GuidelyContext);
|
|
4361
4686
|
const ref = useRef5(handler);
|
|
4362
4687
|
ref.current = handler;
|
|
4363
|
-
|
|
4688
|
+
useEffect8(() => {
|
|
4364
4689
|
if (!client) return;
|
|
4365
4690
|
return client.on(event, ((...args) => ref.current(...args)));
|
|
4366
4691
|
}, [client, event]);
|
|
4367
4692
|
}
|
|
4368
4693
|
function useGuidelyScreen(name, properties) {
|
|
4369
4694
|
const client = useContext2(GuidelyContext);
|
|
4370
|
-
|
|
4695
|
+
useEffect8(() => {
|
|
4371
4696
|
if (client && name) client.screen(name, properties);
|
|
4372
4697
|
}, [client, name]);
|
|
4373
4698
|
}
|
|
@@ -4379,15 +4704,15 @@ function useGuidelyNavigation(navigationRef, options = {}) {
|
|
|
4379
4704
|
const route = navigationRef.getCurrentRoute?.();
|
|
4380
4705
|
if (client && route?.name) client.screen(nameRef.current ? nameRef.current(route) : route.name);
|
|
4381
4706
|
};
|
|
4382
|
-
|
|
4707
|
+
useEffect8(report, [client]);
|
|
4383
4708
|
return { onReady: report, onStateChange: report };
|
|
4384
4709
|
}
|
|
4385
4710
|
function useUiSelector(select, fallback) {
|
|
4386
4711
|
const client = useContext2(GuidelyContext);
|
|
4387
4712
|
const selectRef = useRef5(select);
|
|
4388
4713
|
selectRef.current = select;
|
|
4389
|
-
const [value, setValue] =
|
|
4390
|
-
|
|
4714
|
+
const [value, setValue] = useState7(() => client ? select(client) : fallback);
|
|
4715
|
+
useEffect8(() => {
|
|
4391
4716
|
if (!client) return;
|
|
4392
4717
|
let last = JSON.stringify(selectRef.current(client));
|
|
4393
4718
|
setValue(selectRef.current(client));
|